{"record":{"id":"2a3be78ebb648bb1","repo":"nautechsystems/nautilus_trader","slug":"cannot-represent-durations-greater-than-584-years","errorCode":null,"errorMessage":"Cannot represent durations greater than 584 years","messagePattern":"Cannot represent durations greater than 584 years","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/network/src/ratelimiter/clock.rs","lineNumber":112,"sourceCode":"///\n/// The mock time is represented as an atomic u64 count of nanoseconds, behind an [`Arc`].\n/// Clones of this clock will all show the same time, even if the original advances.\n#[derive(Debug, Clone, Default)]\npub struct FakeRelativeClock {\n    now: Arc<AtomicU64>,\n}\n\nimpl FakeRelativeClock {\n    /// Advances the fake clock by the given amount.\n    ///\n    /// # Panics\n    ///\n    /// Panics if `by` cannot be represented as a `u64` number of nanoseconds (i.e., exceeds 584 years).\n    pub fn advance(&self, by: Duration) {\n        let by: u64 = by\n            .as_nanos()\n            .try_into()\n            .expect(\"Cannot represent durations greater than 584 years\");\n\n        let mut prev = self.now.load(Ordering::Acquire);\n        let mut next = prev + by;\n\n        while let Err(e) =\n            self.now\n                .compare_exchange_weak(prev, next, Ordering::Release, Ordering::Relaxed)\n        {\n            prev = e;\n            next = prev + by;\n        }\n    }\n}\n\nimpl PartialEq for FakeRelativeClock {\n    fn eq(&self, other: &Self) -> bool {\n        self.now.load(Ordering::Relaxed) == other.now.load(Ordering::Relaxed)\n    }","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/network/src/ratelimiter/clock.rs#L94-L130","documentation":"The mock/quanta clock's advance() converts the Duration to u64 nanoseconds and panics if it exceeds u64::MAX nanoseconds (~584 years). The clock's internal state is a u64 nanosecond counter, so longer jumps are unrepresentable.","triggerScenarios":"Calling RateLimiter clock advance(by) (public) with a Duration whose as_nanos() > u64::MAX — practically only with absurdly large Durations; called in tests via test_ensure_window_current and by sleep().","commonSituations":"Writing tests that simulate long time jumps (e.g. Duration::from_secs(u64::MAX) or from_secs_f64 with huge values); misconfigured timeout/backoff values that overflow when converted to nanos.","solutions":["Cap the advance duration below u64::MAX nanoseconds (~584 years).","In tests, advance in steps (e.g. loop advancing 1 year) instead of one giant jump.","Check where the Duration is built; a unit conversion bug (secs treated as nanos, or from_secs_f64 of a huge number) is usually the cause."],"exampleFix":"// before\nclock.advance(Duration::from_secs_f64(1e12)); // > 584 years in nanos? panics\n// after\nlet by = Duration::from_secs_f64(1e12);\nassert!(by.as_nanos() <= u64::MAX as u128, \"advance exceeds clock range\");\nclock.advance(by);","handlingStrategy":"validation","validationCode":"fn advance_safe(clock: &QuantaClock, by: Duration) {\n    assert!(by.as_nanos() <= u64::MAX as u128, \"advance exceeds u64 nanos\");\n    clock.advance(by);\n}","typeGuard":"fn representable(d: &Duration) -> bool { d.as_nanos() <= u64::MAX as u128 }","tryCatchPattern":"let result = std::panic::catch_unwind(|| clock.advance(by));","preventionTips":["Sanity-check computed durations; check for unit conversion mistakes","Advance mock clocks in bounded steps in tests","Never build Durations from unchecked external numeric config"],"tags":["rust","duration","overflow","clock","rate-limiting"],"backgroundTag":"value-out-of-range","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}