Skip to content

Include the underlying reason in invalid --changed-before/-within date errors#2054

Open
momomuchu wants to merge 3 commits into
sharkdp:masterfrom
momomuchu:fix/invalid-date-error-message-2053
Open

Include the underlying reason in invalid --changed-before/-within date errors#2054
momomuchu wants to merge 3 commits into
sharkdp:masterfrom
momomuchu:fix/invalid-date-error-message-2053

Conversation

@momomuchu

@momomuchu momomuchu commented Jul 4, 2026

Copy link
Copy Markdown

fd --changed-before=2025-11-31 (an invalid calendar date) prints a generic "'...' is not a valid date or duration" and hides the actual reason.

TimeFilter::from_str returned Option<SystemTime> via .ok()?, discarding the underlying parse errors from all four format attempts (span, timestamp, datetime, @timestamp). It now returns Result<_, String> and, on total failure, surfaces the DateTime parser's error, which is the most relevant one for calendar-date-shaped input.

Before: '2025-11-31' is not a valid date or duration. See 'fd --help'.
After: '2025-11-31' is not a valid date or duration: parsed date is not valid: parameter 'day' for '2025-11' is invalid, must be in range 1..=30. See 'fd --help'.

Added a unit test asserting the error for an out-of-range calendar date includes the reason. cargo test, clippy (-Dwarnings) and fmt clean. CHANGELOG entry added.

Note on non-calendar input: the surfaced reason is always the DateTime (calendar) parser's error. That is precise for calendar-shaped mistakes (2025-13-01, 2025-02-30, ...), but for input that is not date-shaped at all (e.g. a mistyped duration like 5xyz) the reason reads as failed to parse year in date, which is a bit off-topic. It is still strictly more informative than the old generic message; if you'd prefer, I can use a neutral fallback wording for the non-calendar case instead.

Closes #2053

…hin dates

Previously an invalid date like 2025-11-31 (November has 30 days) was
rejected with a generic 'is not a valid date or duration' message,
discarding the actual reason. Surface the inner parser error instead,
e.g. 'day ... is invalid, must be in range 1..=30', so the user can
tell it's an out-of-range calendar date rather than a formatting issue.

Fixes sharkdp#2053
Comment thread src/filter/time.rs Outdated
/// source of confusing failures, e.g. `2025-11-31` which is not a valid
/// calendar date) instead of silently discarding it, so callers can tell
/// the user *why* their input was rejected.
fn from_str(s: &str) -> Result<SystemTime, String> {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the error type a string, and not an anyhow error or jiff::Error?

Comment thread src/filter/time.rs
}

#[test]
fn invalid_calendar_date_error_includes_inner_reason() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test seems a little brittle. If the jiff error messages change, then this test could fail on a version update.

Comment thread src/filter/time.rs Outdated
// parser gives the most useful reason for calendar-date-
// shaped input (the common case for this kind of mistake),
// so surface that instead of a generic message.
Err(datetime_err.to_string())

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this error message always user-friendly, or are there cases where this could expose implementation details.

Comment thread src/filter/time.rs
{
return Ok(UNIX_EPOCH + Duration::from_secs(timestamp_secs));
}
// None of the supported formats matched. The `DateTime`

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could however be more confusing if the user meant to use a span, or timestamp.

momomuchu added 2 commits July 5, 2026 14:26
Addresses review comments on sharkdp#2054. TimeFilter::from_str/before/after
now return anyhow::Result instead of Result<_, String>, matching the
error convention used elsewhere in the crate (e.g. walk.rs). Call
sites in main.rs already compile unchanged since anyhow::Error's
Display shows the same top-level message a String did.

Also relax the calendar-date test: instead of asserting the message
contains "day" (coupled to jiff's exact wording), it now checks the
message is non-empty and differs from the message for an unrelated
malformed input, which still proves the inner reason is surfaced
without breaking on a jiff wording change.
The previous version only checked that two invalid inputs produce
different messages, which still passes if the code drops the real
parse reason but keeps echoing the raw input. Compare two dates that
are invalid for the same reason (day 31 in a 30-day month) against one
invalid for a different reason (month 13), and require the same-reason
pair to share substantially more text. Still avoids asserting on jiff's
exact wording.
@momomuchu

Copy link
Copy Markdown
Author

Thanks, good points. 1. Error type: switched from_str/before/after to anyhow::Result - the rest of the crate already uses anyhow (main.rs, walk.rs), String was the outlier. main.rs needed no change since anyhow::Error's Display gives the same message; fd is bin-only so no API concern. 2. Test brittleness: reworked it so it no longer matches jiff's literal wording - it checks that two dates invalid for the same reason share more of the message than a date invalid for a different reason (computed common-substring length), so it survives a jiff reword but still proves the real parse reason is surfaced, not just the echoed input. 3. Error message exposure: no sensitive data - the appended text only echoes the user's own input plus generic range wording (must be in range 1..=30), no paths or secrets. 4. Span/timestamp confusion: fair - a malformed span/timestamp currently shows the calendar-date parser reason, which can read off-topic. I can gate the appended reason to only show when the input looks date-shaped, with a neutral fallback otherwise. Want that in this PR or a follow-up?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] fd should print more specific error messages for --changed- date parsing

2 participants