nautechsystems/nautilus_trader · critical

Failed to set spread quote vega pricing timeout

Error message

Failed to set spread quote vega pricing timeout

What it means

After computing the vega pricing timeout alert time, the aggregator arms it with `LiveClock::set_time_alert_ns` and `.expect`s success. An Err means the clock could not register the alert (internal clock error or lifecycle problem), so the vega pricing timeout would never fire and quotes could hang waiting for stale greeks.

Source

Thrown at crates/data/src/aggregation.rs:2432

        };
        let callback = TimeEventCallback::RustLocal(Rc::new(move |_event: TimeEvent| {
            if let Some(agg) = aggregator_weak.upgrade() {
                agg.borrow_mut().clear_vega_pricing_timeout();
            }
        }));
        let timeout = DurationNanos::try_from_secs(self.vega_pricing_timeout_seconds)
            .expect("vega pricing timeout exceeds the nanosecond range");
        let alert_time = self.clock.borrow().timestamp_ns() + timeout;

        self.clock
            .borrow_mut()
            .set_time_alert_ns(
                &self.vega_pricing_timeout_timer_name,
                alert_time,
                Some(callback),
                Some(true),
            )
            .expect("Failed to set spread quote vega pricing timeout");
    }

    fn create_futures_spread_prices(&self) -> (f64, f64) {
        let mut raw_ask = 0.0_f64;
        let mut raw_bid = 0.0_f64;

        for i in 0..self.leg_ids.len() {
            let r = self.ratios[i] as f64;
            if self.ratios[i] >= 0 {
                raw_ask += r * self.ask_prices[i];
                raw_bid += r * self.bid_prices[i];
            } else {
                raw_ask += r * self.bid_prices[i];
                raw_bid += r * self.ask_prices[i];
            }
        }
        (raw_bid, raw_ask)
    }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure the aggregator cancels its vega timeout alert on stop and uses a unique timer name per instance/instrument
  2. Verify shutdown ordering: disarm alerts before clock teardown
  3. Log the underlying `set_time_alert_ns` error (replace expect with match/log) to pinpoint the cause
  4. If triggered by an invalid alert_time, fix the timeout seconds config (see the duration overflow error)
Defensive patterns

Strategy: try-catch

Validate before calling

// Rust: ensure prior alert cancelled before re-arming
assert!(alerts_cleared.contains(&agg.vega_pricing_timeout_timer_name()), "vega timeout alert still armed");

Try / catch

let result = std::panic::catch_unwind(|| agg.arm_vega_pricing_timeout());
if result.is_err() { log::error!("failed to arm vega pricing timeout alert"); }

Prevention

When it happens

Trigger: Arming the `vega_pricing_timeout_timer_name` alert during spread quote initialization in live mode when the clock returns Err — duplicate alert name, clock already shut down, or a timer-name collision from restarting the aggregator without cleanup.

Common situations: Restarting a spread subscription without the previous alert being cancelled (name collision); teardown/shutdown races; misconfigured timeout producing an alert_time the clock rejects.

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/431d87eadae377c3. Report an issue: GitHub.