{"record":{"id":"3f49f1975a0fa65f","repo":"quickwit-oss/quickwit","slug":"invalid-duration-num-str","errorCode":null,"errorMessage":"Invalid duration: {num_str}","messagePattern":"Invalid duration: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"quickwit/quickwit-serve/src/jaeger_api/parse_duration.rs","lineNumber":58,"sourceCode":"    for ch in input.trim().chars() {\n        if ch.is_ascii_digit() || ch == '.' || ch == '-' {\n            num_str.push(ch);\n            continue;\n        }\n        if ch.is_alphabetic() {\n            let unit = &input[num_str.len()..];\n            let num: f64 = num_str.parse()?;\n            let duration: f64 = match unit {\n                \"ns\" => num,\n                \"us\" | \"µs\" => num * 1000.0,\n                \"ms\" => num * 1_000_000.0,\n                \"s\" => num * 1_000_000_000.0,\n                \"m\" => num * 60.0 * 1_000_000_000.0,\n                \"h\" => num * 3600.0 * 1_000_000_000.0,\n                _ => anyhow::bail!(\"Invalid time unit: {}\", unit),\n            };\n            if num < i64::MIN as f64 || num > i64::MAX as f64 {\n                anyhow::bail!(\"Invalid duration: {}\", num_str)\n            }\n            return Ok(duration.round() as i64);\n        } else {\n            anyhow::bail!(\"Invalid duration string\")\n        }\n    }\n    anyhow::bail!(\"Invalid duration string\")\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::jaeger_api::parse_duration::parse_duration_nanos;\n\n    #[test]\n    fn test_parse_duration_nanos() {\n        // Test valid duration strings\n        assert_eq!(parse_duration_nanos(\"300ns\").unwrap(), 300);\n        assert_eq!(parse_duration_nanos(\"1us\").unwrap(), 1000);","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/quickwit-oss/quickwit/blob/a39730c5cdcd1a4fe798403737ae293999ea21f8/quickwit/quickwit-serve/src/jaeger_api/parse_duration.rs#L40-L76","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Send a duration whose numeric value fits within ±9.2e18, and preferably a sane duration like `168h` instead of huge second counts.","Express long ranges with a larger unit to shrink the number (e.g., `9999999999999999s` → `285616h` is still valid, but prefer realistic lookbacks).","Fix the client code that computes the duration so it clamps or validates the value before formatting.","Check the request for accidental duplication/mis-scaling of the numeric component."],"exampleFix":"// before\nlet dur = format!(\"{}s\", millis_since_epoch * 1000);\n\n// after\nlet dur = format!(\"{}h\", elapsed_hours);","handlingStrategy":"validation","validationCode":"let num: f64 = num_str.parse()?;\nif !num.is_finite() || num < i64::MIN as f64 || num > i64::MAX as f64 {\n    return Err(format!(\"duration number '{}' out of i64 range\", num_str));\n}","typeGuard":null,"tryCatchPattern":"match parse_duration_with_units(input) {\n    Ok(d) => use_duration(d),\n    Err(e) if e.to_string().contains(\"Invalid duration:\") => {\n        eprintln!(\"Duration number in '{}' out of range; use a smaller value or larger unit\", input);\n        clamped_duration()\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Clamp or sanitize computed durations client-side before formatting the string.","Use larger units (h) for long ranges instead of enormous second/millisecond counts.","Never pass epoch-like magnitudes where a duration is expected.","Range-check numeric components against i64 bounds in client code."],"tags":["jaeger","duration-parsing","overflow","rust"],"backgroundTag":"value-out-of-range","analyzedSha":"a39730c5cdcd1a4fe798403737ae293999ea21f8","analyzedAt":"2026-09-08T13:19:37.784Z","contentChangedAt":"2026-09-08T13:19:37.784Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}