nautechsystems/nautilus_trader · error · anyhow::Error

Binance {field} timestamp is outside the UnixNanos range: {v

Error message

Binance {field} timestamp is outside the UnixNanos range: {value}

What it means

A Binance timestamp parses to a value that, once scaled from milliseconds/microseconds to nanoseconds, falls outside the UnixNanos representable range (i64 nanoseconds since epoch). The value is non-negative but absurdly large, so the checked constructor returns None and this error reports the overflow.

Source

Thrown at crates/adapters/binance/src/common/parse.rs:92

pub(crate) fn parse_millis(value: i64, field: &str) -> anyhow::Result<UnixNanos> {
    parse_timestamp(value, UnixNanos::from_millis_checked(value), field)
}

pub(crate) fn parse_micros(value: i64, field: &str) -> anyhow::Result<UnixNanos> {
    parse_timestamp(value, UnixNanos::from_micros_checked(value), field)
}

fn parse_timestamp(
    value: i64,
    timestamp: Option<UnixNanos>,
    field: &str,
) -> anyhow::Result<UnixNanos> {
    timestamp.ok_or_else(|| {
        if value < 0 {
            anyhow::anyhow!("invalid negative Binance {field} timestamp: {value}")
        } else {
            anyhow::anyhow!("Binance {field} timestamp is outside the UnixNanos range: {value}")
        }
    })
}

pub(crate) fn parse_millis_or_init(value: i64, field: &str, ts_init: UnixNanos) -> UnixNanos {
    timestamp_or_init(parse_millis(value, field), ts_init)
}

pub(crate) fn parse_micros_or_init(value: i64, field: &str, ts_init: UnixNanos) -> UnixNanos {
    timestamp_or_init(parse_micros(value, field), ts_init)
}

fn timestamp_or_init(timestamp: anyhow::Result<UnixNanos>, ts_init: UnixNanos) -> UnixNanos {
    match timestamp {
        Ok(timestamp) => timestamp,
        Err(e) => {
            log::warn!("{e}; using initialization timestamp");
            ts_init

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Inspect the raw value printed in the message and compare with the expected unit for that field (Binance uses ms for REST, us for some stream payloads)
  2. Verify the data path - captures, proxies, or transformations between Binance and the adapter that could alter numbers
  3. If the field is legitimately huge garbage from upstream, report it; do not clamp silently

Example fix

// before
let ts = parse_millis(value, "workingTime")?; // value actually microseconds

// after
let ts = parse_micros(value, "workingTime")?; // match the field's real unit
Defensive patterns

Strategy: type-guard

Validate before calling

fn is_plausible_millis(value: i64) -> bool {
    // reject values that cannot scale into i64 nanoseconds: |value| < i64::MAX / 1_000_000
    value >= 0 && value <= i64::MAX / 1_000_000
}

Type guard

fn is_plausible_unit_timestamp(value: i64, unit_multiplier: i64) -> bool {
    value >= 0 && value.checked_mul(unit_multiplier).is_some()
}

Try / catch

let ts = match parse_millis(value, field) {
    Ok(ts) => ts,
    Err(e) => {
        log::error!("implausible {field} value {value}: {e} - probable unit mismatch or corrupt payload");
        ts_init // explicit fallback, never a silent clamp
    }
};

Prevention

When it happens

Trigger: A millis/micros field containing a garbage-huge number, or a value in the wrong unit (e.g. nanoseconds fed where millis are expected) so the x1e6/x1e3 scaling overflows; corrupted or tampered payloads.

Common situations: Unit confusion when mapping fields from Binance's mixed ms/us APIs; corrupted captures; a proxy/gateway mangling numeric fields; clock-source bugs producing nonsense values.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16). Data as JSON: /api/errors/aad26c6591640e49. Report an issue: GitHub.