{"record":{"id":"d19f6191b2938768","repo":"nautechsystems/nautilus_trader","slug":"failed-to-set-spread-quote-timer","errorCode":null,"errorMessage":"Failed to set spread quote timer","messagePattern":"Failed to set spread quote timer","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/data/src/aggregation.rs","lineNumber":2190,"sourceCode":"        }));\n\n        let now_ns = self.clock.borrow().timestamp_ns();\n        let interval_ns = DurationNanos::from_secs(interval_secs);\n        let start_time =\n            now_ns.floor(interval_ns) + DurationNanos::from_micros(self.quote_build_delay);\n        let fire_immediately = now_ns == start_time;\n        self.clock\n            .borrow_mut()\n            .set_timer_ns(\n                &self.timer_name,\n                interval_ns,\n                Some(start_time),\n                None,\n                Some(callback),\n                Some(true),\n                Some(fire_immediately),\n            )\n            .expect(\"Failed to set spread quote timer\");\n    }\n\n    /// Called when the timer fires (live mode). Builds and sends a spread quote using the timer event timestamp.\n    pub fn on_timer_fire(&mut self, ts_event: UnixNanos) {\n        if self.last_quotes.len() == self.leg_ids.len() {\n            self.build_and_send_quote(ts_event);\n        }\n    }\n\n    /// Stops the timer when in timer-driven mode.\n    pub fn stop_timer(&mut self) {\n        if self.update_interval_seconds.is_some()\n            && self\n                .clock\n                .borrow()\n                .timer_names()\n                .contains(&self.timer_name.as_str())\n        {","sourceCodeStart":2172,"sourceCodeEnd":2208,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/data/src/aggregation.rs#L2172-L2208","documentation":"The futures-spread quote aggregator sets a recurring timer on the live clock to drive quote generation; `set_timer_ns` returns a Result and the code `.expect`s success. A failure means the live clock refused or failed to register the timer (e.g. already in a bad state or internal clock error), which would silently stop spread quotes.","triggerScenarios":"Calling the spread quote aggregator's timer setup (during spread subscription/startup in live mode) when `LiveClock::set_timer_ns` returns Err — e.g. registering a duplicate timer name, or the clock being shut down mid-setup.","commonSituations":"Starting a spread aggregator twice for the same instrument (duplicate timer name); shutting down the node while a spread subscription is being initialized; clock lifecycle races in live adapters.","solutions":["Ensure the spread aggregator is started/stopped exactly once per instrument; check for duplicate subscriptions of the same spread instrument","Verify clean shutdown ordering: cancel timers/stop aggregators before tearing down the clock","Inspect the inner clock error (wrap the expect with a match/log) to identify the exact `set_timer_ns` failure reason","Upgrade/retry the subscription after a shutdown race; if reproducible, report as a NautilusTrader bug"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Rust: ensure single registration per instrument before start\nassert!(!active_spreads.contains(&instrument_id), \"spread aggregator already started for {instrument_id}\");","typeGuard":null,"tryCatchPattern":"let result = std::panic::catch_unwind(|| agg.set_spread_quote_timer());\nif result.is_err() { log::error!(\"spread quote timer setup failed\"); }","preventionTips":["Start/stop each spread aggregator exactly once","Cancel timers before clock teardown on shutdown","Log the underlying set_timer_ns error for diagnosis"],"tags":["rust","panic","timer","live-clock","data-engine"],"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"}