{"record":{"id":"1e153b26027e8250","repo":"nautechsystems/nautilus_trader","slug":"millisecond-timestamp-overflowed","errorCode":null,"errorMessage":"millisecond timestamp overflowed","messagePattern":"millisecond timestamp overflowed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/bybit/src/websocket/parse.rs","lineNumber":680,"sourceCode":"            rho: 0.0, // Bybit doesn't provide rho\n        },\n        mark_iv: Some(mark_iv),\n        bid_iv: Some(bid_iv),\n        ask_iv: Some(ask_iv),\n        underlying_price: Some(underlying_price),\n        open_interest: Some(open_interest),\n        ts_event,\n        ts_init,\n    })\n}\n\npub(crate) fn parse_millis_i64(value: i64, field: &str) -> anyhow::Result<UnixNanos> {\n    if value < 0 {\n        Err(anyhow::anyhow!(\"{field} must be non-negative, was {value}\"))\n    } else {\n        let nanos = (value as u64)\n            .checked_mul(NANOSECONDS_IN_MILLISECOND)\n            .ok_or_else(|| anyhow::anyhow!(\"millisecond timestamp overflowed\"))?;\n        Ok(UnixNanos::from(nanos))\n    }\n}\n\n/// Parses a WebSocket kline payload into a [`Bar`].\n///\n/// # Errors\n///\n/// Returns an error if price or volume fields cannot be parsed or if the bar cannot be constructed.\npub fn parse_ws_kline_bar(\n    kline: &BybitWsKline,\n    instrument: &InstrumentAny,\n    bar_type: BarType,\n    timestamp_on_close: bool,\n    ts_init: UnixNanos,\n) -> anyhow::Result<Bar> {\n    let price_precision = instrument.price_precision();\n    let size_precision = instrument.size_precision();","sourceCodeStart":662,"sourceCodeEnd":698,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/bybit/src/websocket/parse.rs#L662-L698","documentation":"parse_millis_i64 multiplies the millisecond value by 1,000,000 to obtain nanoseconds using checked arithmetic on u64. If the resulting nanosecond value exceeds u64 range, this overflow error is thrown.","triggerScenarios":"A WebSocket payload (orderbook, trade tick, quote) carrying a millisecond timestamp larger than u64::MAX/1e6 (~1.8e13 ms, year ~539000) passed to parse_millis_i64.","commonSituations":"Upstream sending microseconds/nanoseconds mislabeled as milliseconds; unit-encoding schema changes; fabricated or fuzzed payloads with absurd timestamps.","solutions":["Log the raw value and verify its actual time unit against Bybit's API docs","Convert with the correct unit multiplier if the field is actually microseconds/nanoseconds","Add an upper-bound sanity check (e.g. reject timestamps far in the future) before conversion"],"exampleFix":"// before: assumes milliseconds, overflows on microsecond input\nlet ts = parse_millis_i64(raw.ts, \"ts\")?;\n// after: correct unit for microsecond fields\nlet ts = parse_micros_i64(raw.ts, \"ts\")?;","handlingStrategy":"validation","validationCode":"def plausible_millis(v: int) -> bool:\n    return 0 <= v <= 4_102_444_800_000  # up to year 2100","typeGuard":"def is_plausible_timestamp(v) -> bool:\n    return isinstance(v, int) and 0 <= v <= 4_102_444_800_000","tryCatchPattern":"match parse_millis_i64(raw.ts, \"ts\") {\n    Err(e) if e.to_string().contains(\"overflowed\") => { log_unit_mismatch(raw.ts); skip },\n    other => other?,\n}","preventionTips":["Bound-check timestamps against a sane wall-clock window before conversion","Confirm the time unit (ms vs us vs ns) after any Bybit API change","Add fuzz/property tests with extreme timestamp values"],"tags":["rust","bybit","websocket","overflow","timestamp"],"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"}