nautechsystems/nautilus_trader · critical
Failed to set spread quote timer
Error message
Failed to set spread quote timer
What it means
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.
Source
Thrown at crates/data/src/aggregation.rs:2190
}));
let now_ns = self.clock.borrow().timestamp_ns();
let interval_ns = DurationNanos::from_secs(interval_secs);
let start_time =
now_ns.floor(interval_ns) + DurationNanos::from_micros(self.quote_build_delay);
let fire_immediately = now_ns == start_time;
self.clock
.borrow_mut()
.set_timer_ns(
&self.timer_name,
interval_ns,
Some(start_time),
None,
Some(callback),
Some(true),
Some(fire_immediately),
)
.expect("Failed to set spread quote timer");
}
/// Called when the timer fires (live mode). Builds and sends a spread quote using the timer event timestamp.
pub fn on_timer_fire(&mut self, ts_event: UnixNanos) {
if self.last_quotes.len() == self.leg_ids.len() {
self.build_and_send_quote(ts_event);
}
}
/// Stops the timer when in timer-driven mode.
pub fn stop_timer(&mut self) {
if self.update_interval_seconds.is_some()
&& self
.clock
.borrow()
.timer_names()
.contains(&self.timer_name.as_str())
{View on GitHub (pinned to 18893faf8b)
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
Defensive patterns
Strategy: try-catch
Validate before calling
// Rust: ensure single registration per instrument before start
assert!(!active_spreads.contains(&instrument_id), "spread aggregator already started for {instrument_id}"); Try / catch
let result = std::panic::catch_unwind(|| agg.set_spread_quote_timer());
if result.is_err() { log::error!("spread quote timer setup failed"); } Prevention
- Start/stop each spread aggregator exactly once
- Cancel timers before clock teardown on shutdown
- Log the underlying set_timer_ns error for diagnosis
When it happens
Trigger: 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.
Common situations: 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.
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
- timer event sender was unset for Rust callback system
- Callback should exist
- Failed to set spread quote vega pricing timeout
- Event '{}' should have associated handler
- timer queue peeked Some but pop returned None
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/d19f6191b2938768.
Report an issue: GitHub.