{"record":{"id":"d4e3e65823f9dc8f","repo":"nautechsystems/nautilus_trader","slug":"timer-exists-at-timestamp","errorCode":null,"errorMessage":"timer exists at timestamp","messagePattern":"timer exists at timestamp","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/backtest/src/engine.rs","lineNumber":1698,"sourceCode":"                self.last_ns = t;\n                self.flush_accumulator_events(clocks, t)?;\n                Ok(false)\n            }\n        }\n    }\n\n    fn run_timer_handlers_at(\n        &mut self,\n        clocks: &[Rc<RefCell<dyn Clock>>],\n        ts_event: UnixNanos,\n        advance_to: UnixNanos,\n    ) {\n        self.last_ns = ts_event;\n        while self.accumulator.peek_next_time() == Some(ts_event) {\n            let handler = self\n                .accumulator\n                .pop_next_at_or_before(ts_event)\n                .expect(\"timer exists at timestamp\");\n            Self::set_all_clocks_time(clocks, ts_event);\n            logging_clock_set_static_time(ts_event.as_u64());\n            handler.run();\n            self.drain_command_queues();\n\n            if self.kernel.is_shutdown_requested() {\n                return;\n            }\n\n            for clock in clocks {\n                Self::advance_clock_on_accumulator(&mut self.accumulator, clock, advance_to, false);\n            }\n        }\n    }\n\n    fn finalize_timestamp(\n        &mut self,\n        clocks: &[Rc<RefCell<dyn Clock>>],","sourceCodeStart":1680,"sourceCodeEnd":1716,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/backtest/src/engine.rs#L1680-L1716","documentation":"BacktestEngine::run_timer_handlers_at pops due time events from the accumulator after peeking that the accumulator's next time equals ts_event. The expect asserts the pop always succeeds right after the successful peek. Failure would mean the accumulator was drained between the peek and the pop, or peek/pop disagree — an internal consistency bug in the timer loop.","triggerScenarios":"Practically unreachable through the public run() API; would require peek_next_time() and pop_next_at_or_before() to disagree, e.g. via a logic regression or external mutation of the accumulator during the loop (called from advance_time_impl, flush_accumulator_events, finalize_timestamp).","commonSituations":"Only after an engine internals change/regression or a custom subclass interfering with the accumulator. Not a user configuration error.","solutions":["Ensure no code calls accumulator methods concurrently with engine time advancement","File a minimal reproduction as a bug report if hit","Upgrade to a version where the peek/pop mismatch is fixed"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"// Users cannot peek/pop the accumulator directly; ensure timers are only scheduled\n// via the engine API and never cancelled externally mid-run:\nassert!(clock.timer_count() >= 0, \"clock state sanity\");","typeGuard":null,"tryCatchPattern":"// Panic not catchable in normal Rust; reproduce with a timer-only backtest and report.","preventionTips":["Schedule/cancel timers only through engine and clock public APIs","Do not share the TestClock with code that mutates timers during a run","Upgrade if a regression is reported upstream"],"tags":["rust","panic","backtest","timers","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}