{"record":{"id":"a189e273814d5973","repo":"nautechsystems/nautilus_trader","slug":"microseconds-micros-is-out-of-range-for-u64-na","errorCode":null,"errorMessage":"microseconds {micros} is out of range for `u64` nanoseconds","messagePattern":"microseconds (.+?) is out of range for `u64` nanoseconds","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/core/src/datetime.rs","lineNumber":361,"sourceCode":"///\n/// Returns an error if `micros` is non-finite or cannot be represented as `u64` nanoseconds.\n#[expect(\n    clippy::cast_possible_truncation,\n    clippy::cast_sign_loss,\n    clippy::cast_precision_loss,\n    reason = \"Intentional for unit conversion, may lose precision after clamping\"\n)]\npub fn micros_to_nanos(micros: f64) -> anyhow::Result<u64> {\n    anyhow::ensure!(\n        micros.is_finite(),\n        \"microseconds must be finite, was {micros}\"\n    );\n\n    if micros <= 0.0 {\n        return Ok(0);\n    }\n    let nanos = micros * NANOSECONDS_IN_MICROSECOND as f64;\n    anyhow::ensure!(\n        nanos < U64_UPPER_BOUND_F64,\n        \"microseconds {micros} is out of range for `u64` nanoseconds\"\n    );\n    Ok(nanos.trunc() as u64)\n}\n\n/// Converts microseconds (μs) to nanoseconds (ns), panicking on invalid input.\n///\n/// # Panics\n///\n/// Panics if [`micros_to_nanos`] would return an error for `micros`.\n#[must_use]\npub fn micros_to_nanos_unchecked(micros: f64) -> u64 {\n    micros_to_nanos(micros).expect(\"micros_to_nanos_unchecked: invalid or overflowing input\")\n}\n\n/// Converts nanoseconds (ns) to seconds.\n///","sourceCodeStart":343,"sourceCodeEnd":379,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/core/src/datetime.rs#L343-L379","documentation":"micros_to_nanos multiplies by 1e3 and stores in u64, capped at ~1.8446744e19 nanoseconds (about 1.8446744e16 microseconds). This error means the input microseconds exceed the u64 range after conversion.","triggerScenarios":"Calling micros_to_nanos with micros such that micros * 1e3 >= U64_UPPER_BOUND_F64 (micros >= ~1.8446744e16).","commonSituations":"Unit confusion — passing a nanosecond timestamp (1.7e18) as microseconds; passing millisecond values where microseconds are expected repeatedly compounded by conversions; unvalidated numeric input from config or feeds.","solutions":["Verify the input unit; if the value is already nanoseconds, skip the conversion.","Range-check the microsecond value before conversion and reject/clamp implausible values.","Standardize on one time unit (nanoseconds u64) across the codebase to avoid repeated conversions."],"exampleFix":"// before\nlet ns = micros_to_nanos(ns_value as f64)?; // overflow\n// after\nlet ns = ns_value; // already nanoseconds","handlingStrategy":"validation","validationCode":"const MAX_MICROS_F64: f64 = 1.8446744e16; // u64::MAX nanoseconds in microseconds\nif !micros.is_finite() || micros < 0.0 || micros >= MAX_MICROS_F64 {\n    return Err(format!(\"microseconds out of convertible range: {micros}\"));\n}","typeGuard":"fn is_convertible_micros(x: f64) -> bool { x.is_finite() && x > 0.0 && x < 1.8446744e16 }","tryCatchPattern":"let ns = match micros_to_nanos(micros) {\n    Ok(ns) => ns,\n    Err(e) if e.to_string().contains(\"out of range\") => { log::error!(\"unit confusion? micros={micros}\"); bail!(e); }\n    Err(e) => return Err(e),\n};","preventionTips":["Verify units at boundaries; ns-scale values (~1e18) passed as micros overflow.","Range-check numeric feed/config values before conversion.","Use native u64 nanosecond timestamps throughout to avoid repeated f64 conversions."],"tags":["rust","datetime","overflow","unit-conversion"],"backgroundTag":"value-out-of-range","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}