{"record":{"id":"2642f06e2420a23e","repo":"nautechsystems/nautilus_trader","slug":"microsecond-timestamp-micros-overflows-when-scal","errorCode":null,"errorMessage":"microsecond timestamp {micros} overflows when scaled to nanoseconds","messagePattern":"microsecond timestamp (.+?) overflows when scaled to nanoseconds","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/lighter/src/common/parse.rs","lineNumber":185,"sourceCode":"/// 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///\n/// # Errors\n///\n/// Returns an error if `secs * 1_000_000_000` would overflow `u64`.\npub fn parse_secs_to_nanos(secs: u64) -> anyhow::Result<UnixNanos> {\n    let nanos = secs.checked_mul(NANOSECONDS_IN_SECOND).ok_or_else(|| {\n        anyhow::anyhow!(\"second timestamp {secs} overflows when scaled to nanoseconds\")\n    })?;\n    Ok(UnixNanos::from(nanos))\n}\n\n/// Converts a signed Unix millisecond timestamp into [`UnixNanos`].\n///","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/lighter/src/common/parse.rs#L167-L203","documentation":"parse_micros_to_nanos converts a microsecond timestamp to UnixNanos via micros.checked_mul(1_000). When that multiplication would overflow u64 the error is raised instead of allowing silent wraparound. Only values above u64::MAX / 1_000 (~1.8e16 microseconds) trigger it, far beyond any real timestamp.","triggerScenarios":"Calling parse_micros_to_nanos directly (its only caller is the test parse_micros_to_nanos_rejects_overflow) with micros > ~1.8e16, i.e. a corrupt or deliberately oversized value.","commonSituations":"Feeding nanosecond values into the microsecond converter; corrupted venue payloads; overflow unit tests.","solutions":["Confirm the timestamp unit; if the source value is already nanoseconds, use it directly without scaling.","Validate/bound the incoming timestamp before conversion.","For testing, keep values below u64::MAX / 1_000."],"exampleFix":"// before\nlet ts = parse_micros_to_nanos(nanos_value)?; // value is already nanos\n// after\nlet ts = UnixNanos::from(nanos_value);","handlingStrategy":"validation","validationCode":"fn micros_plausible(us: u64) -> bool { us < u64::MAX / 1_000 && us > 1_400_000_000_000_000 }","typeGuard":"fn is_micros(v: u64) -> bool { (1_400_000_000_000_000..u64::MAX / 1_000).contains(&v) }","tryCatchPattern":"match parse_micros_to_nanos(micros) {\n    Ok(ts) => ts,\n    Err(e) => { warn!(\"micros overflow: {e}\"); UnixNanos::default() }\n}","preventionTips":["Do not feed nanosecond values into the microsecond converter","Bound-check microsecond timestamps before scaling","Only real-time-scale values should ever reach this function"],"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"}