nautechsystems/nautilus_trader · error

DurationNanos overflow in from_millis

Error message

DurationNanos overflow in from_millis

What it means

`DurationNanos::from_millis` converts whole milliseconds (u64) into a nanosecond-based duration. It is a panicking (`#[must_use] const fn`) wrapper around the fallible `try_from_millis`, so when `millis * 1_000_000` exceeds `DurationNanos::MAX` it intentionally panics rather than returning a Result. The library throws it because the requested duration cannot be represented in the u64 nanosecond domain.

Source

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

    /// Creates a duration from a number of whole microseconds.
    ///
    /// # Errors
    ///
    /// Returns an error if the result exceeds [`DurationNanos::MAX`].
    pub const fn try_from_micros(micros: u64) -> Result<Self, DurationNanosOutOfRangeError> {
        Self::try_from_units(micros, NANOSECONDS_IN_MICROSECOND, "microseconds")
    }

    /// Creates a duration from a number of whole milliseconds.
    ///
    /// # Panics
    ///
    /// Panics if the result exceeds [`DurationNanos::MAX`].
    #[must_use]
    pub const fn from_millis(millis: u64) -> Self {
        match Self::try_from_millis(millis) {
            Ok(duration) => duration,
            Err(_) => panic!("DurationNanos overflow in from_millis"),
        }
    }

    /// Creates a duration from a number of whole milliseconds.
    ///
    /// # Errors
    ///
    /// Returns an error if the result exceeds [`DurationNanos::MAX`].
    pub const fn try_from_millis(millis: u64) -> Result<Self, DurationNanosOutOfRangeError> {
        Self::try_from_units(millis, NANOSECONDS_IN_MILLISECOND, "milliseconds")
    }

    /// Creates a duration from a number of whole seconds.
    ///
    /// # Panics
    ///
    /// Panics if the result exceeds [`DurationNanos::MAX`].
    #[must_use]

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Use the fallible `DurationNanos::try_from_millis(millis)` and handle the Err case instead of panicking.
  2. Validate the input before calling: reject values greater than `u64::MAX / 1_000_000`.
  3. Correct the unit of the upstream value (config/env often passes nanos or micros mislabeled as millis).
  4. Clamp the value to `DurationNanos::MAX` nanoseconds converted back to milliseconds if saturation is acceptable.

Example fix

// before
let dur = DurationNanos::from_millis(cfg_timeout_ms);

// after
let dur = DurationNanos::try_from_millis(cfg_timeout_ms)
    .unwrap_or(DurationNanos::MAX); // or surface the error to the caller
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

fn fits_duration_millis(m: u64) -> Option<DurationNanos> {
    DurationNanos::try_from_millis(m).ok()
}

Prevention

When it happens

Trigger: Calling `DurationNanos::from_millis(m)` where `m > u64::MAX / 1_000_000` (i.e. `m >= 18_446_744_073_709` ms, roughly 213.5 days), so the millisecond-to-nanosecond multiplication overflows u64 and the `Err(_)` arm of the match panics.

Common situations: Computing a timeout/backoff from a user- or config-supplied millisecond value with no upper bound check; multiplying durations (e.g. days or weeks expressed in ms) before passing them in; fuzzing or property tests with u64::MAX; config files where a value is accidentally in nanoseconds or microseconds instead of milliseconds.

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