nautechsystems/nautilus_trader · error

millisecond timestamp overflowed

Error message

millisecond timestamp overflowed

What it means

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.

Source

Thrown at crates/adapters/bybit/src/websocket/parse.rs:680

            rho: 0.0, // Bybit doesn't provide rho
        },
        mark_iv: Some(mark_iv),
        bid_iv: Some(bid_iv),
        ask_iv: Some(ask_iv),
        underlying_price: Some(underlying_price),
        open_interest: Some(open_interest),
        ts_event,
        ts_init,
    })
}

pub(crate) fn parse_millis_i64(value: i64, field: &str) -> anyhow::Result<UnixNanos> {
    if value < 0 {
        Err(anyhow::anyhow!("{field} must be non-negative, was {value}"))
    } else {
        let nanos = (value as u64)
            .checked_mul(NANOSECONDS_IN_MILLISECOND)
            .ok_or_else(|| anyhow::anyhow!("millisecond timestamp overflowed"))?;
        Ok(UnixNanos::from(nanos))
    }
}

/// Parses a WebSocket kline payload into a [`Bar`].
///
/// # Errors
///
/// Returns an error if price or volume fields cannot be parsed or if the bar cannot be constructed.
pub fn parse_ws_kline_bar(
    kline: &BybitWsKline,
    instrument: &InstrumentAny,
    bar_type: BarType,
    timestamp_on_close: bool,
    ts_init: UnixNanos,
) -> anyhow::Result<Bar> {
    let price_precision = instrument.price_precision();
    let size_precision = instrument.size_precision();

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Log the raw value and verify its actual time unit against Bybit's API docs
  2. Convert with the correct unit multiplier if the field is actually microseconds/nanoseconds
  3. Add an upper-bound sanity check (e.g. reject timestamps far in the future) before conversion

Example fix

// before: assumes milliseconds, overflows on microsecond input
let ts = parse_millis_i64(raw.ts, "ts")?;
// after: correct unit for microsecond fields
let ts = parse_micros_i64(raw.ts, "ts")?;
Defensive patterns

Strategy: validation

Validate before calling

def plausible_millis(v: int) -> bool:
    return 0 <= v <= 4_102_444_800_000  # up to year 2100

Type guard

def is_plausible_timestamp(v) -> bool:
    return isinstance(v, int) and 0 <= v <= 4_102_444_800_000

Try / catch

match parse_millis_i64(raw.ts, "ts") {
    Err(e) if e.to_string().contains("overflowed") => { log_unit_mismatch(raw.ts); skip },
    other => other?,
}

Prevention

When it happens

Trigger: 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.

Common situations: Upstream sending microseconds/nanoseconds mislabeled as milliseconds; unit-encoding schema changes; fabricated or fuzzed payloads with absurd timestamps.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/1e153b26027e8250. Report an issue: GitHub.