jdx/mise · error · eyre::Report

Invalid date or duration: {s}. Expected formats: '2024-06-01

Error message

Invalid date or duration: {s}. Expected formats: '2024-06-01', '2024-06-01T12:00:00Z', '90d', '1y'

What it means

`parse_into_timestamp` (src/duration.rs:59) tries four parsers in order — RFC3339 `Timestamp`, `Zoned` datetime, `civil::Date` (YYYY-MM-DD, treated as end of day UTC), then jiff `Span`. When all four fail it bails with the list of accepted formats, so this error means the string matched no supported date or duration grammar.

Source

Thrown at src/duration.rs:90

        let datetime = civil_date.at(23, 59, 59, 0);
        let ts = datetime.to_zoned(jiff::tz::TimeZone::UTC)?.timestamp();
        return Ok(ts);
    }

    // Subtract the duration from `process_now` so the same relative
    // duration resolves to the same absolute Timestamp every time.
    if let Ok(span) = s.parse::<Span>() {
        // Validate that duration is positive (negative would result in future date)
        let duration = span.to_duration(date(2025, 1, 1))?;
        if duration.is_negative() {
            bail!("duration must not be negative: {}", s);
        }
        let now_zoned = process_now().to_zoned(jiff::tz::TimeZone::UTC);
        let past = now_zoned.checked_sub(span)?;
        return Ok(past.timestamp());
    }

    bail!(
        "Invalid date or duration: {s}. Expected formats: '2024-06-01', '2024-06-01T12:00:00Z', '90d', '1y'"
    )
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_process_now_is_stable() {
        let a = process_now();
        std::thread::sleep(std::time::Duration::from_millis(5));
        let b = process_now();
        assert_eq!(a, b);
    }

    #[test]
    fn test_parse_into_timestamp_relative_is_stable() {

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Use one of the listed forms exactly: `2024-06-01`, `2024-06-01T12:00:00Z`, `90d`, `1y`
  2. For composite relative spans use jiff span syntax without spaces/commas (e.g. `1y6m`)
  3. Validate calendar dates (month 1-12, day valid for the month) before pasting them in

Example fix

# before
expiry = "06/01/2024"
# after
expiry = "2024-06-01"
Defensive patterns

Strategy: validation

Validate before calling

# preflight date/duration strings with the same grammar mise accepts
import re, sys
ok = re.fullmatch(r"\d{4}-\d{2}-\d{2}(T[\d:]+Z?)?|\d+[smhdwy]", s)
if not ok: sys.exit(f"invalid date/duration: {s}")

Type guard

fn parses_as_timestamp(s: &str) -> bool {
    s.parse::<jiff::Timestamp>().is_ok()
        || s.parse::<jiff::Zoned>().is_ok()
        || s.parse::<jiff::civil::Date>().is_ok()
        || s.parse::<jiff::Span>().is_ok()
}

Prevention

When it happens

Trigger: A date/duration setting receiving an unparseable string: `"2024-13-01"` (invalid month), `"06/01/2024"` (US format), `"in 90d"`, `"90 days"` in a form jiff's Span rejects, or a bare number where a span/date is required.

Common situations: Human-friendly strings copied from other tools' docs; locale-formatted dates; missing or doubled units (`90dd`); timezone names instead of offsets; values from CI variables that were never validated.

Related errors


AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17). Data as JSON: /api/errors/9ac32270e996951c. Report an issue: GitHub.