{"record":{"id":"589eee6e070c6716","repo":"quickwit-oss/quickwit","slug":"invalid-duration-string","errorCode":null,"errorMessage":"Invalid duration string","messagePattern":"Invalid duration string","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"quickwit/quickwit-serve/src/jaeger_api/parse_duration.rs","lineNumber":62,"sourceCode":"        }\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);\n        assert_eq!(parse_duration_nanos(\"2.5ms\").unwrap(), 2500000);\n        assert_eq!(parse_duration_nanos(\"3s\").unwrap(), 3000000000);\n        assert_eq!(parse_duration_nanos(\"4m\").unwrap(), 240000000000);\n        assert_eq!(parse_duration_nanos(\"5h\").unwrap(), 18000000000000);","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/quickwit-oss/quickwit/blob/a39730c5cdcd1a4fe798403737ae293999ea21f8/quickwit/quickwit-serve/src/jaeger_api/parse_duration.rs#L44-L80","documentation":"`parse_duration_nanos` walks the input characters: digits, `.`, and `-` accumulate the numeric part; the first alphabetic character starts the unit suffix. Any non-digit, non-`.`/`-`, non-alphabetic character (space in the middle, `+`, `_`, etc.), or a string with no alphabetic unit at all (e.g. `\"100\"` or `\"abc\"`), falls through to `bail!(\"Invalid duration string\")`. Both the mid-loop and end-of-input paths use this same generic message.","triggerScenarios":"Sending the Jaeger API a duration string that is not `<number><unit>`: a bare number like `\"300\"` (missing unit), a string like `\"1.2.3s\"` (double dot breaks f64 parse), `\"abc\"` (no leading digits, so the first char is alphabetic but unit match fails / num parse fails), or containing spaces/`+` such as `\"5 min\"`.","commonSituations":"Query params with URL-decoded spaces (`lookback=1%20h`); clients omitting the unit entirely (Go `time.Duration` users sending nanosecond ints as strings); typo'd values like `\"1-.23s\"`; empty strings reaching the parser.","solutions":["Include a valid unit suffix on the number: `\"300\"` → `\"300ms\"`, `\"1 h\"` → `\"1h\"`.","Remove whitespace and illegal characters; only `[-0-9.]` then `[a-z]` units are accepted.","Fix malformed numbers like `1.2.3s` to a single decimal `1.23s`.","Validate/normalize duration strings on the client before issuing Jaeger API requests; if the input is a plain number, decide the intended unit explicitly."],"exampleFix":"// before\nlookback=1%20h   // \"1 h\"\n\n// after\nlookback=1h","handlingStrategy":"validation","validationCode":"let re = regex::Regex::new(r\"^-?\\d+(\\.\\d+)?(ns|us|µs|ms|s|m|h)$\").unwrap();\nif !re.is_match(duration_str.trim()) {\n    return Err(format!(\"malformed duration '{}': expected e.g. 300ms, -1.5h\", duration_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 string\") => {\n        eprintln!(\"'{}' is not <number><unit> (e.g. 300ms); stripping whitespace/unitless values\", input);\n        normalize_then_retry(input)\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always pair a number with a unit; never send bare numeric strings.","Trim and strip whitespace from durations before sending (spaces are rejected).","Avoid multiple dots or stray signs in the numeric part (e.g. 1.2.3s).","Share one duration-formatting helper across all Jaeger API calls so the format is consistent."],"tags":["jaeger","duration-parsing","input-validation","rust"],"backgroundTag":"invalid-duration-format","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"}