{"record":{"id":"2da41e7d2d7e7c3c","repo":"nautechsystems/nautilus_trader","slug":"seconds-secs-is-out-of-range-for-u64-nanosecon","errorCode":null,"errorMessage":"seconds {secs} is out of range for `u64` nanoseconds","messagePattern":"seconds (.+?) is out of range for `u64` nanoseconds","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/core/src/datetime.rs","lineNumber":236,"sourceCode":"\n/// Converts seconds to nanoseconds (ns).\n///\n/// # Errors\n///\n/// Returns an error if `secs` 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 secs_to_nanos(secs: f64) -> anyhow::Result<u64> {\n    anyhow::ensure!(secs.is_finite(), \"seconds must be finite, was {secs}\");\n    if secs <= 0.0 {\n        return Ok(0);\n    }\n    let nanos = secs * NANOSECONDS_IN_SECOND as f64;\n    anyhow::ensure!(\n        nanos < U64_UPPER_BOUND_F64,\n        \"seconds {secs} is out of range for `u64` nanoseconds\"\n    );\n    Ok(nanos.trunc() as u64)\n}\n\n/// Converts seconds to milliseconds (ms).\n///\n/// # Errors\n///\n/// Returns an error if `secs` is non-finite or cannot be represented as `u64` milliseconds.\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 secs_to_millis(secs: f64) -> anyhow::Result<u64> {","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/core/src/datetime.rs#L218-L254","documentation":"secs_to_nanos multiplies seconds by 1e9 and stores the result in u64, whose maximum is ~1.8446744e19 nanoseconds (about 584 years). This error means the input seconds, converted to nanoseconds, exceeds the u64 upper bound, so the conversion would overflow.","triggerScenarios":"Calling secs_to_nanos with secs such that secs * 1e9 >= U64_UPPER_BOUND_F64 — i.e. roughly secs >= 1.8446744e10 seconds.","commonSituations":"Passing a UNIX epoch timestamp (~1.7e9 seconds) is safe, but passing a timestamp in milliseconds mistakenly as seconds (e.g. 1.7e12) overflows; misconfigured far-future expiry dates encoded as raw seconds.","solutions":["Verify the unit of the input; if a millisecond timestamp was passed as seconds, divide by 1000 first.","Clamp or reject timestamps above ~1.84e10 seconds before the call.","Use u64 nanos-since-epoch semantics (Unix epoch) rather than arbitrary large durations."],"exampleFix":"// before\nlet ns = secs_to_nanos(ms_timestamp as f64)?; // overflow\n// after\nlet ns = secs_to_nanos(ms_timestamp as f64 / 1_000.0)?;","handlingStrategy":"validation","validationCode":"const MAX_SECS_F64: f64 = 1.8446744e10; // u64::MAX nanoseconds in seconds\nif !secs.is_finite() || secs < 0.0 || secs >= MAX_SECS_F64 {\n    return Err(format!(\"seconds out of convertible range: {secs}\"));\n}","typeGuard":"fn is_convertible_secs(x: f64) -> bool { x.is_finite() && x > 0.0 && x < 1.8446744e10 }","tryCatchPattern":"let ns = match secs_to_nanos(secs) {\n    Ok(ns) => ns,\n    Err(e) if e.to_string().contains(\"out of range\") => u64::MAX, // clamp, or bail\n    Err(e) => return Err(e),\n};","preventionTips":["Confirm units (seconds vs ms vs us vs ns) at every API boundary.","UNIX epoch seconds (~1.7e9) are safe; anything above ~1.8e10 will overflow.","Store timestamps as typed u64 nanosecond values rather than raw f64."],"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-14T00:17:10.932Z"}