{"record":{"id":"9e808c160569f2c6","repo":"nautechsystems/nautilus_trader","slug":"datetime-timestamp-out-of-range-for-unixnanos-na","errorCode":null,"errorMessage":"DateTime timestamp out of range for UnixNanos: {nanos}","messagePattern":"DateTime timestamp out of range for UnixNanos: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/core/src/datetime.rs","lineNumber":681,"sourceCode":"        .and_then(|nanos| u64::try_from(nanos).ok())\n        .map(UnixNanos::from)\n}\n\n/// Converts a `Timestamp` to `UnixNanos`.\n///\n/// Unlike `UnixNanos::from(Timestamp)` which panics, this returns an error.\n///\n/// # Errors\n///\n/// Returns an error if the timestamp is before the UNIX epoch or out of range for `UnixNanos`.\npub fn try_datetime_to_unix_nanos(value: Timestamp) -> anyhow::Result<UnixNanos> {\n    let nanos = value.as_nanosecond();\n\n    if nanos < 0 {\n        anyhow::bail!(\"DateTime timestamp cannot be negative: {nanos}\");\n    }\n    let nanos = u64::try_from(nanos)\n        .map_err(|_| anyhow::anyhow!(\"DateTime timestamp out of range for UnixNanos: {nanos}\"))?;\n\n    Ok(UnixNanos::from(nanos))\n}\n\n#[cfg(test)]\n// `allow` not `expect`: nightly clippy does not fire `float_cmp` inside `assert_eq!`\n#[allow(\n    clippy::float_cmp,\n    reason = \"Exact float comparisons acceptable in tests\"\n)]\nmod tests {\n    use jiff::SignedDuration;\n    use proptest::prelude::*;\n    use rstest::rstest;\n\n    use super::*;\n\n    fn timestamp(value: &str) -> Timestamp {","sourceCodeStart":663,"sourceCodeEnd":699,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/core/src/datetime.rs#L663-L699","documentation":"`try_datetime_to_unix_nanos` converts a DateTime into the library's `UnixNanos` (u64 nanoseconds since epoch). It rejects negative timestamps outright, and errors with this message when the nanosecond value is positive but exceeds what a u64 can represent (or otherwise cannot be converted from i64). The library throws it to prevent silently wrapping/overflowing the internal u64 timestamp representation.","triggerScenarios":"Calling `try_datetime_to_unix_nanos` with a DateTime whose `as_nanosecond()` value is greater than u64::MAX nanoseconds (roughly year 2554). Negative timestamps get a different message, so this one specifically fires on far-future dates.","commonSituations":"Constructing expiry or alert times with an overly large year (e.g. misparsing a year like '99999' or unit confusion, milliseconds treated as nanoseconds multiplied incorrectly); using a far-future sentinel 'never expires' timestamp; passing a datetime built from unvalidated user input.","solutions":["Clamp or validate the DateTime to a sane range (e.g. before year 2554 / u64::MAX ns) before converting","Check unit conversions: ensure you are not multiplying milliseconds or seconds by an extra 1e9 factor","Use a smaller sentinel value (e.g. a few years in the future) for 'max' expiry semantics","If you need beyond-u64-nanosecond ranges, handle the error and switch to a different representation"],"exampleFix":"// before\nlet nanos = try_datetime_to_unix_nanos(far_future_dt)?;\n// after\nlet max_dt = DateTime::from_timestamp(9223372036, 0).unwrap(); // well within u64 ns\nlet nanos = try_datetime_to_unix_nanos(dt.min(max_dt))?;","handlingStrategy":"validation","validationCode":"let nanos = value.as_nanosecond();\nif nanos < 0 || nanos > i64::from(u64::MAX) {\n    // clamp or reject before calling try_datetime_to_unix_nanos\n}\nlet unix_nanos = try_datetime_to_unix_nanos(value)?;","typeGuard":"fn is_representable_as_unix_nanos(value: &DateTime) -> bool {\n    let nanos = value.as_nanosecond();\n    nanos >= 0 && u64::try_from(nanos).is_ok()\n}","tryCatchPattern":"match try_datetime_to_unix_nanos(dt) {\n    Ok(nanos) => use(nanos),\n    Err(e) => tracing::error!(\"timestamp out of range: {e}\"), // clamp/fallback\n}","preventionTips":["Validate datetime ranges at config-parse time, not deep in the call chain","Beware unit conversions that inflate ms/s values into nanoseconds","Use bounded sentinel values for 'never expires' semantics"],"tags":["rust","datetime","overflow","value-out-of-range"],"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"}