nautechsystems/nautilus_trader · error · anyhow::Error

Timestamp overflow for '{ts}'

Error message

Timestamp overflow for '{ts}'

What it means

After parsing the millisecond value as u64, parse_timestamp_ms multiplies by NANOSECONDS_IN_MILLISECOND using checked_mul. If the millisecond value is so large that the nanosecond product overflows u64, it refuses to produce a wrapped value and returns this overflow error.

Source

Thrown at crates/adapters/polymarket/src/websocket/parse.rs:50

use serde::Serialize;

use super::messages::{
    PolymarketBestBidAsk, PolymarketBookLevel, PolymarketBookSnapshot, PolymarketQuote,
    PolymarketTrade,
};
use crate::common::{
    enums::PolymarketOrderSide,
    parse::{determine_trade_id, parse_decimal_exact},
};

/// Parses a millisecond epoch timestamp string into [`UnixNanos`].
pub fn parse_timestamp_ms(ts: &str) -> anyhow::Result<UnixNanos> {
    let ms: u64 = ts
        .parse()
        .map_err(|e| anyhow::anyhow!("Invalid timestamp '{ts}': {e}"))?;
    let ns = ms
        .checked_mul(NANOSECONDS_IN_MILLISECOND)
        .ok_or_else(|| anyhow::anyhow!("Timestamp overflow for '{ts}'"))?;
    Ok(UnixNanos::from(ns))
}

pub(crate) fn parse_price(s: &str, precision: u8) -> CorrectnessResult<Price> {
    let value = parse_decimal_exact(s).map_err(|e| CorrectnessError::PredicateViolation {
        message: format!("Invalid price '{s}': {e}"),
    })?;
    Price::from_decimal_dp(value, precision)
}

pub(crate) fn parse_quantity(s: &str, precision: u8) -> CorrectnessResult<Quantity> {
    let value = parse_decimal_exact(s).map_err(|e| CorrectnessError::PredicateViolation {
        message: format!("Invalid quantity '{s}': {e}"),
    })?;
    Quantity::from_decimal_dp(value, precision)
}

pub(crate) fn verify_book_snapshot_hash(

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the ts string in the error — an absurd value usually means a corrupted or malicious payload
  2. Drop/skip the message rather than failing the stream for out-of-range timestamps
  3. Ensure you pass milliseconds, not nanoseconds or microseconds (adjust conversion)
  4. Pre-validate the magnitude: reject ms > 253_402_300_728_999 (year 9999) as obviously invalid

Example fix

// before: giant sentinel value overflows
let ts = parse_timestamp_ms("18446744073709551615")?;
// after: pre-validate plausible range
let ms: u64 = ts_str.parse()?;
anyhow::ensure!(ms <= 4102444800000, "timestamp far in future: {ms}");
let ts = parse_timestamp_ms(ts_str)?;
Defensive patterns

Strategy: validation

Validate before calling

let ms: u64 = ts_str.parse()?;
anyhow::ensure!(ms <= 4102444800000, "implausible timestamp: {ms}");

Type guard

fn plausible_millis(raw: &str) -> bool {
    matches!(raw.parse::<u64>(), Ok(ms) if ms <= 4102444800000)
}

Try / catch

match parse_timestamp_ms(ts) {
    Ok(nanos) => /* proceed */,
    Err(e) if e.to_string().contains("overflow") => {
        log::error!("corrupt/giant timestamp dropped: {e}");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling parse_timestamp_ms with a millisecond value greater than u64::MAX / 1_000_000 (≈ 18,446,744,073,709 ms ≈ year 584,542,048 in epoch ms) — practically only from corrupted or malicious payloads, or a string with many digits.

Common situations: Fuzzed or adversarial WebSocket payloads with absurd timestamps; a unit bench test using sentinel values like u64::MAX; accidental unit confusion (nanoseconds passed where milliseconds are expected).

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/e74c6f54a227ce88. Report an issue: GitHub.