nautechsystems/nautilus_trader · error

Time event accumulator sequence overflow

Error message

Time event accumulator sequence overflow

What it means

TimeEventAccumulator::push assigns each queued time event handler a monotonically increasing u64 sequence number used as a FIFO tie-breaker in the min-heap. The sequence counter is incremented with checked_add, and this panic fires only after u64::MAX pushes have occurred, exhausting the sequence space. It is effectively an internal invariant that can never be hit in a realistic backtest.

Source

Thrown at crates/backtest/src/accumulator.rs:90

    }
}

impl TimeEventAccumulator {
    /// Creates a new [`TimeEventAccumulator`] instance.
    #[must_use]
    pub fn new() -> Self {
        Self {
            heap: BinaryHeap::new(),
            next_sequence: 0,
        }
    }

    fn push(&mut self, handler: TimeEventHandler) {
        let sequence = self.next_sequence;
        self.next_sequence = self
            .next_sequence
            .checked_add(1)
            .expect("Time event accumulator sequence overflow");
        self.heap
            .push(Reverse(AccumulatedTimeEventHandler { handler, sequence }));
    }

    /// Advance the given clock to the `to_time_ns` and push events to the heap.
    pub fn advance_clock(&mut self, clock: &mut TestClock, to_time_ns: UnixNanos, set_time: bool) {
        let events = clock.advance_time(to_time_ns, set_time);
        let handlers = clock.match_handlers(events);
        for handler in handlers {
            self.push(handler);
        }
    }

    /// Peek at the next event timestamp without removing it.
    ///
    /// Returns `None` if the heap is empty.
    #[must_use]
    pub fn peek_next_time(&self) -> Option<UnixNanos> {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Treat as an internal invariant; no user action is needed for realistic workloads
  2. Split work across multiple accumulator instances if an astronomically long run is genuinely required
  3. Report to maintainers if encountered, since reaching u64::MAX sequences indicates a runaway event loop
Defensive patterns

Strategy: retry

Validate before calling

// Not guardable by users; a u64 sequence overflow requires ~2^64 pushes.
// Assert sanity in long-running jobs:
assert!(accumulator_events_pushed < u64::MAX / 2, "runaway event loop suspected");

Try / catch

// Panics are not catchable in normal Rust; ensure the event loop terminates.
if events_pushed > threshold { log::error!("unbounded timer scheduling detected"); std::process::abort(); }

Prevention

When it happens

Trigger: Calling push (directly or via advance_clock) approximately 2^64 times within the lifetime of a single TimeEventAccumulator instance; no realistic workload reaches this.

Common situations: Only conceivable in an extremely long-running backtest with an unbounded timer-scheduling loop, or in a custom/stress test that intentionally drives next_sequence to u64::MAX. Not a real-world configuration or usage issue.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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