astrid-runtime/astrid · error

unknown duration suffix: {other}

Error message

unknown duration suffix: {other}

What it means

Unknown-suffix arm of parse_duration's chunk parser: the trailing alphabetic unit after a numeric component (case-insensitively) is not one of ms, s, m, h, or their accepted variants. E.g. "30sec" or "2w". The parser fails rather than guessing a unit, since misinterpreting a duration would corrupt quota TTLs.

Source

Thrown at crates/astrid-cli/src/commands/quota.rs:419

        suffix.push(c);
        while let Some(&n) = iter.peek() {
            if n.is_ascii_alphabetic() {
                suffix.push(n);
                iter.next();
            } else {
                break;
            }
        }
        let num: f64 = current
            .parse()
            .with_context(|| format!("invalid duration component: {current}"))?;
        let chunk = match suffix.to_ascii_lowercase().as_str() {
            "ms" => Duration::from_secs_f64(num / 1000.0),
            "s" => Duration::from_secs_f64(num),
            "m" => Duration::from_secs_f64(num * 60.0),
            "h" => Duration::from_secs_f64(num * 3600.0),
            "d" => Duration::from_secs_f64(num * 86_400.0),
            other => anyhow::bail!("unknown duration suffix: {other}"),
        };
        total = total.saturating_add(chunk);
        current.clear();
    }
    if !current.is_empty() {
        // Trailing bare number without suffix → seconds.
        let secs: u64 = current.parse().context("trailing number without suffix")?;
        total = total.saturating_add(Duration::from_secs(secs));
    }
    Ok(total)
}

/// Render a byte count as a human-readable string with binary units.
#[expect(
    clippy::cast_precision_loss,
    reason = "human-readable rendering, magnitude up to ~GiB"
)]
fn format_bytes(b: u64) -> String {

View on GitHub (pinned to affd8760f4)

Solutions

  1. Use only ms, s, m, h, d suffixes (e.g. `5m` not `5min`)
  2. Split unsupported units: `1w` -> `7d`
  3. Remember bare integers are treated as seconds, so `300` works for 5 minutes

Example fix

// before
astrid quota set --timeout 5min
// after
astrid quota set --timeout 5m
Defensive patterns

Strategy: validation

Validate before calling

const DUR_SUFFIXES: [&str; 5] = ["MS","S","M","H","D"];
fn chunks_valid(spec: &str) -> bool {
    spec.split(|c: char| c.is_ascii_digit() || c == '.')
        .filter(|p| !p.is_empty())
        .all(|s| DUR_SUFFIXES.contains(&s.to_ascii_uppercase().as_str()))
}

Prevention

When it happens

Trigger: `--timeout 5min`, `--timeout 2hr`, `--timeout 1w`, or mixing in unsupported units in compound forms like `1h30mins`.

Common situations: Writing natural-language units (min, sec, weeks), translating from other tools' duration syntax (Go accepts `us`/`µs`, this parser does not), or typos like `30sec`.

Understand the failure class

Background: "invalid duration" / "failed to parse duration": why your timeout, interval, or TTL string is rejected and which formats each library accepts — this error's family across 32 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/d65c1e1a8303f79d. Report an issue: GitHub.