quickwit-oss/quickwit · warning

Invalid duration: {num_str}

Error message

Invalid duration: {num_str}

What it means

After the unit suffix matches and the numeric part is scaled to nanoseconds, the code checks that the resulting value fits in an `i64`. Here the check is actually on the raw number `num` (before scaling) against `i64::MIN`/`i64::MAX`; if the numeric literal is out of that range the parse bails with the numeric string embedded in the message. It guards against f64/i64 overflow when converting to nanosecond timestamps.

Source

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

    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() {
        // Test valid duration strings
        assert_eq!(parse_duration_nanos("300ns").unwrap(), 300);
        assert_eq!(parse_duration_nanos("1us").unwrap(), 1000);

View on GitHub (pinned to a39730c5cd)

Solutions

  1. Send a duration whose numeric value fits within ±9.2e18, and preferably a sane duration like `168h` instead of huge second counts.
  2. Express long ranges with a larger unit to shrink the number (e.g., `9999999999999999s` → `285616h` is still valid, but prefer realistic lookbacks).
  3. Fix the client code that computes the duration so it clamps or validates the value before formatting.
  4. Check the request for accidental duplication/mis-scaling of the numeric component.

Example fix

// before
let dur = format!("{}s", millis_since_epoch * 1000);

// after
let dur = format!("{}h", elapsed_hours);
Defensive patterns

Strategy: validation

Validate before calling

let num: f64 = num_str.parse()?;
if !num.is_finite() || num < i64::MIN as f64 || num > i64::MAX as f64 {
    return Err(format!("duration number '{}' out of i64 range", num_str));
}

Try / catch

match parse_duration_with_units(input) {
    Ok(d) => use_duration(d),
    Err(e) if e.to_string().contains("Invalid duration:") => {
        eprintln!("Duration number in '{}' out of range; use a smaller value or larger unit", input);
        clamped_duration()
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Passing an extremely large (or extremely negative) numeric duration to the Jaeger API, e.g. `lookback=99999999999999999999s` or a duration whose magnitude exceeds `i64` (~9.2e18), where `num_str.parse::<f64>()` yields a value outside the `i64` range.

Common situations: Bug in a calling script constructing durations (unbounded multiplication of milliseconds since epoch etc.); a client sending raw epoch-like values as durations; fat-fingered extra digits in a duration.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of quickwit-oss/quickwit@a39730c5cd (2026-09-08). Data as JSON: /api/errors/3f49f1975a0fa65f. Report an issue: GitHub.