{"record":{"id":"82204404b25e40c4","repo":"nautechsystems/nautilus_trader","slug":"millisecond-timestamp-millis-overflows-when-scal","errorCode":null,"errorMessage":"millisecond timestamp {millis} overflows when scaled to nanoseconds","messagePattern":"millisecond timestamp (.+?) overflows when scaled to nanoseconds","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/lighter/src/common/parse.rs","lineNumber":173,"sourceCode":"        \"size precision {precision} exceeds maximum {MAX_DECIMALS}\",\n    );\n    anyhow::ensure!(value.is_sign_positive(), \"negative quantity `{value}`\");\n    Quantity::from_decimal_dp(value, precision)\n        .map_err(|e| anyhow::anyhow!(\"invalid quantity `{value}` at precision {precision}: {e}\"))\n}\n\n/// Converts a Unix millisecond timestamp into [`UnixNanos`].\n///\n/// # Errors\n///\n/// Returns an error if `millis * 1_000_000` would overflow `u64`. Realistic\n/// venue timestamps are nowhere near this bound; the check rejects malformed\n/// payloads instead of silently wrapping in release builds.\npub fn parse_millis_to_nanos(millis: u64) -> anyhow::Result<UnixNanos> {\n    let nanos = millis\n        .checked_mul(NANOSECONDS_IN_MILLISECOND)\n        .ok_or_else(|| {\n            anyhow::anyhow!(\"millisecond timestamp {millis} overflows when scaled to nanoseconds\")\n        })?;\n    Ok(UnixNanos::from(nanos))\n}\n\n/// Converts a Unix microsecond timestamp into [`UnixNanos`].\n///\n/// # Errors\n///\n/// Returns an error if `micros * 1_000` would overflow `u64`.\npub fn parse_micros_to_nanos(micros: u64) -> anyhow::Result<UnixNanos> {\n    let nanos = micros.checked_mul(1_000).ok_or_else(|| {\n        anyhow::anyhow!(\"microsecond timestamp {micros} overflows when scaled to nanoseconds\")\n    })?;\n    Ok(UnixNanos::from(nanos))\n}\n\n/// Converts a Unix second timestamp into [`UnixNanos`].\n///","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/lighter/src/common/parse.rs#L155-L191","documentation":"parse_millis_to_nanos scales a millisecond timestamp to nanoseconds using checked multiplication. If millis * 1_000_000 would overflow u64 the conversion is rejected rather than silently wrapping in release builds. Real venue timestamps are nowhere near this bound, so this almost always indicates malformed input.","triggerScenarios":"Calling parse_millis_to_nanos or its callers (parse_optional_millis_to_nanos, parse_trade_tick, parse_candle_bar, parse_ws_order_book_deltas, parse_ws_order_book_depth10) with a millis value greater than u64::MAX / 1_000_000 (~1.8e13 ms, year ~2262+) — e.g. a garbage or corrupted timestamp field in a venue payload.","commonSituations":"Corrupted websocket frames; a venue field misinterpreted (e.g. micros or nanos passed where millis expected, inflating the number); unit tests probing overflow behavior (see parse_millis_to_nanos_rejects_overflow).","solutions":["Verify the timestamp field is actually in milliseconds; if the venue sends microseconds/nanoseconds use parse_micros_to_nanos / parse_secs_to_nanos instead.","Inspect the raw payload for the offending value; treat it as a malformed message and drop/resynchronize.","If intentionally probing limits, keep values below ~1.8e13 milliseconds."],"exampleFix":"// before\nlet ts = parse_millis_to_nanos(venue_nanos_field)?; // field is actually nanos\n// after\nlet ts = UnixNanos::from(venue_nanos_field); // already nanoseconds — no scaling","handlingStrategy":"validation","validationCode":"const MAX_MS: u64 = u64::MAX / 1_000_000; // ~1.8e13\nfn millis_plausible(ms: u64) -> bool { ms < MAX_MS && ms > 1_400_000_000_000 }","typeGuard":"fn is_millis(v: u64) -> bool { (1_400_000_000_000..u64::MAX / 1_000_000).contains(&v) }","tryCatchPattern":"let ts = parse_millis_to_nanos(millis)\n    .or_else(|_| parse_micros_to_nanos(millis).map(|_| unreachable))\n    .unwrap_or_else(|_| { warn!(\"bad timestamp {millis}\"); UnixNanos::default() });","preventionTips":["Confirm timestamp units (ms vs us vs ns) per venue field before choosing the parser","Range-check timestamps against a plausible window (e.g. 2014..2100) before conversion","Use the checked_* based parsers; never hand-multiply timestamps into nanos"],"tags":["timestamp","overflow","parsing","lighter"],"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"}