nautechsystems/nautilus_trader · error

DurationNanos overflow in from_days

Error message

DurationNanos overflow in from_days

What it means

`DurationNanos::from_days` converts whole days (u64) to nanoseconds and panics if `days * 86_400 * 1_000_000_000` exceeds `DurationNanos::MAX`. It mirrors the other panicking constructors: the fallible logic lives in `try_from_days`, and overflow is escalated to a panic for this const API.

Source

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

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

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

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

    const fn try_from_units(
        value: u64,
        nanos_per_unit: u64,
        unit: &'static str,
    ) -> Result<Self, DurationNanosOutOfRangeError> {
        match value.checked_mul(nanos_per_unit) {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Use `DurationNanos::try_from_days(days)` and handle Err.
  2. Validate `days <= u64::MAX / 86_400_000_000_000` before calling.
  3. Clamp to `DurationNanos::MAX` when 'maximum representable' is the intent.
  4. Correct the upstream unit (e.g. value is already in hours).

Example fix

// before
let dur = DurationNanos::from_days(retention_days);

// after
let dur = DurationNanos::try_from_days(retention_days)
    .unwrap_or(DurationNanos::MAX); // saturate 'permanent' retention
Defensive patterns

Strategy: validation

Validate before calling

const MAX_FROM_DAYS: u64 = u64::MAX / 86_400_000_000_000;
fn can_convert_days(d: u64) -> bool { d <= MAX_FROM_DAYS }

Type guard

fn fits_duration_days(d: u64) -> Option<DurationNanos> {
    DurationNanos::try_from_days(d).ok()
}

Prevention

When it happens

Trigger: Calling `DurationNanos::from_days(d)` with `d > u64::MAX / 86_400_000_000_000` (i.e. `d >= 213_503_982` days, about 584 years), causing `try_from_days` to return Err and the panic to fire.

Common situations: Sentinel values like u64::MAX days for 'permanent' retention; misconfigured units (hours/months passed as days); property-based tests over full u64 range.

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