nautechsystems/nautilus_trader · error

UnixNanos overflow in from_millis

Error message

UnixNanos overflow in from_millis

What it means

`UnixNanos::from_millis` converts a millisecond timestamp to nanoseconds via `checked_mul(NANOSECONDS_IN_MILLISECOND)` and panics when the result exceeds u64::MAX. The panic signals that the given millisecond value cannot be represented as UnixNanos; a non-panicking signed variant (`from_millis` on i64 returning Option) exists for error handling.

Source

Thrown at crates/core/src/nanos.rs:443

    /// Panics if the result overflows `u64`.
    #[must_use]
    pub const fn from_seconds(seconds: u64) -> Self {
        match seconds.checked_mul(NANOSECONDS_IN_SECOND) {
            Some(nanos) => Self(nanos),
            None => panic!("UnixNanos overflow in from_seconds"),
        }
    }

    /// Creates a new [`UnixNanos`] from a millisecond timestamp.
    ///
    /// # Panics
    ///
    /// Panics if the result overflows `u64`.
    #[must_use]
    pub const fn from_millis(millis: u64) -> Self {
        match millis.checked_mul(NANOSECONDS_IN_MILLISECOND) {
            Some(nanos) => Self(nanos),
            None => panic!("UnixNanos overflow in from_millis"),
        }
    }

    /// Creates a new [`UnixNanos`] from a signed millisecond timestamp.
    ///
    /// Returns `None` if `millis` is negative or the result overflows `u64`.
    #[must_use]
    pub const fn from_millis_checked(millis: i64) -> Option<Self> {
        Self::from_units_checked(millis, NANOSECONDS_IN_MILLISECOND)
    }

    /// Creates a new [`UnixNanos`] from a microsecond timestamp.
    ///
    /// # Panics
    ///
    /// Panics if the result overflows `u64`.
    #[must_use]
    pub const fn from_micros(micros: u64) -> Self {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check the unit: if the value is already nanoseconds, construct directly with `UnixNanos::new(value)` instead of multiplying again.
  2. Bound-check `millis <= u64::MAX / 1_000_000` before calling.
  3. Use the signed/fallible variant that returns Option and handle None.
  4. Reject implausible timestamps (far beyond current epoch time) during input validation.

Example fix

// before
let ts = UnixNanos::from_millis(raw_ts); // raw_ts already in nanos

// after
let ts = UnixNanos::new(raw_ts); // no unit conversion needed
Defensive patterns

Strategy: validation

Validate before calling

const MAX_UNIXNANOS_MILLIS: u64 = u64::MAX / 1_000_000;
fn valid_epoch_millis(m: u64) -> bool { m <= MAX_UNIXNANOS_MILLIS }

Type guard

fn unix_nanos_from_millis(m: u64) -> Option<UnixNanos> {
    m.checked_mul(1_000_000).map(UnixNanos::new)
}

Prevention

When it happens

Trigger: Calling `UnixNanos::from_millis(m)` with `m > 18_446_744_073_709` (u64::MAX / 1e6), making the checked multiplication fail and the panic arm run.

Common situations: Feeding an already-nanosecond timestamp into from_millis (double conversion), producing a huge number; timestamps parsed from log lines or broker messages with wrong units; u64::MAX sentinel values for 'never expires'.

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