quickwit-oss/quickwit · warning

Invalid time unit: {unit}

Error message

Invalid time unit: {unit}

What it means

`parse_duration_nanos` (used by the Jaeger-compatible API to convert duration strings like `"300ms"` into protobuf `Duration`) accepts only the unit suffixes `ns`, `us`/`µs`, `ms`, `s`, `m`, `h`. When the first non-numeric character begins a suffix not in this set (e.g. `"5min"`, `"2sec"`, `"1H"` — matching is case-sensitive), the matcher falls through to the `_` arm and bails. The error is then wrapped by `parse_duration_with_units` into `"Failed to parse duration: ..."`.

Source

Thrown at quickwit/quickwit-serve/src/jaeger_api/parse_duration.rs:55

/// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
fn parse_duration_nanos(input: &str) -> anyhow::Result<i64> {
    let mut num_str = String::new();
    for ch in input.trim().chars() {
        if ch.is_ascii_digit() || ch == '.' || ch == '-' {
            num_str.push(ch);
            continue;
        }
        if ch.is_alphabetic() {
            let unit = &input[num_str.len()..];
            let num: f64 = num_str.parse()?;
            let duration: f64 = match unit {
                "ns" => num,
                "us" | "µs" => num * 1000.0,
                "ms" => num * 1_000_000.0,
                "s" => num * 1_000_000_000.0,
                "m" => num * 60.0 * 1_000_000_000.0,
                "h" => num * 3600.0 * 1_000_000_000.0,
                _ => anyhow::bail!("Invalid time unit: {}", unit),
            };
            if num < i64::MIN as f64 || num > i64::MAX as f64 {
                anyhow::bail!("Invalid duration: {}", num_str)
            }
            return Ok(duration.round() as i64);
        } else {
            anyhow::bail!("Invalid duration string")
        }
    }
    anyhow::bail!("Invalid duration string")
}

#[cfg(test)]
mod tests {
    use crate::jaeger_api::parse_duration::parse_duration_nanos;

    #[test]
    fn test_parse_duration_nanos() {

View on GitHub (pinned to a39730c5cd)

Solutions

  1. Use a supported unit suffix: ns, us (or µs), ms, s, m, h — e.g. change `30min` to `30m` or `1800s`.
  2. Convert unsupported units before sending: `2d` → `48h`, `1w` → `168h`.
  3. Fix case: units are lowercase and case-sensitive (`5S` → `5s`, `5M` is milliseconds not minutes).
  4. If the value comes from a client tool, configure or patch it to emit Jaeger-spec-compliant durations.

Example fix

// before
lookback=2d

// after
lookback=48h
Defensive patterns

Strategy: validation

Validate before calling

const VALID: &str = "ns|us|µs|ms|s|m|h";
let re = regex::Regex::new(r"^-?\d+(\.\d+)?(ns|us|µs|ms|s|m|h)$").unwrap();
if !re.is_match(duration_str) {
    return Err(format!("duration '{}' must match <num><unit> with units ns|us|ms|s|m|h", duration_str));
}

Try / catch

match parse_duration_with_units(input) {
    Ok(d) => use_duration(d),
    Err(e) if e.to_string().contains("Invalid time unit") => {
        eprintln!("Unsupported unit in '{}'; use ns/us/ms/s/m/h", input);
        default_duration()
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Sending a Jaeger API request (e.g., trace lookup with `lookback=...` or span `duration` min/max parameters) whose duration string ends in an unsupported unit: `min`, `sec`, `d` (days), `w` (weeks), or uppercase variants like `5S` or `5M` (minutes vs milliseconds confusion).

Common situations: A Jaeger client or dashboards emitting Go-style `time.Duration` extended units (days) Quickwit doesn't support; human-written queries using `"30min"` instead of `"30m"`; copy-pasted durations from other systems using different conventions.

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 quickwit-oss/quickwit@a39730c5cd (2026-09-08). Data as JSON: /api/errors/5eb874a09968803a. Report an issue: GitHub.