nautechsystems/nautilus_trader · error

Duration is longer than 584 years

Error message

Duration is longer than 584 years

What it means

The From<Duration> for Nanos conversion in the rate limiter stores time as u64 nanoseconds (governor-style). Any Duration longer than ~584 years cannot fit and the expect panics. This mirrors the underlying u64 nanosecond representation used by the GCRA algorithm.

Source

Thrown at crates/network/src/ratelimiter/nanos.rs:68

    #[inline]
    pub const fn saturating_add(self, rhs: Self) -> Self {
        Self(self.0.saturating_add(rhs.0))
    }

    #[inline]
    pub const fn saturating_mul(self, rhs: u64) -> Self {
        Self(self.0.saturating_mul(rhs))
    }
}

impl From<Duration> for Nanos {
    fn from(d: Duration) -> Self {
        // This will panic:
        Self(
            d.as_nanos()
                .try_into()
                .expect("Duration is longer than 584 years"),
        )
    }
}

impl Debug for Nanos {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
        let d = Duration::from_nanos(self.0);
        write!(f, "Nanos({d:?})")
    }
}

// Add and Mul saturate: release builds disable overflow checks, and a wrapped
// TAT would admit every request; pinning at the far future denies instead.
impl Add<Self> for Nanos {
    type Output = Self;

    fn add(self, rhs: Self) -> Self::Output {
        Self(self.0.saturating_add(rhs.0))

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Clamp or validate the Duration before conversion (as_nanos() <= u64::MAX).
  2. Fix the unit conversion at the source of the Duration.
  3. Represent 'unlimited/never' with the library's dedicated constructs rather than a giant Duration.

Example fix

// before
let nanos: Nanos = my_duration.into(); // panics for > 584 years
// after
assert!(my_duration.as_nanos() <= u64::MAX as u128, "duration exceeds Nanos range");
let nanos: Nanos = my_duration.into();
Defensive patterns

Strategy: validation

Validate before calling

fn to_nanos_safe(d: Duration) -> Option<u64> {
    u64::try_from(d.as_nanos()).ok()
}

Type guard

fn fits_nanos(d: &Duration) -> bool { d.as_nanos() <= u64::MAX as u128 }

Try / catch

let result = std::panic::catch_unwind(|| { let n: Nanos = d.into(); n });

Prevention

When it happens

Trigger: Converting a Duration into Nanos via .into()/From where d.as_nanos() > u64::MAX — e.g. building a Quota with an astronomically large replenish interval, or passing a bad Duration into rate limiter APIs.

Common situations: Configuration mistakes like a period parsed in the wrong unit (seconds value fed as nanoseconds), computed intervals from overflowing arithmetic, or Duration::MAX used as 'never'.

Understand the failure class

Background: "invalid duration" / "failed to parse duration": why your timeout, interval, or TTL string is rejected and which formats each library accepts — this error's family across 32 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/76e263feda2911db. Report an issue: GitHub.