nautechsystems/nautilus_trader · warning

option_summary_family_subs mutex poisoned

Error message

option_summary_family_subs mutex poisoned

What it means

During transport teardown (connect retry or disconnect), the OKX data engine clears the option summary family subscriptions map behind a plain Mutex. This expect panics if that mutex was poisoned by an earlier panic while holding it.

Source

Thrown at crates/adapters/okx/src/data.rs:1125

        if let Some(ref mut ws) = self.ws_business {
            let _result = ws.close().await;
        }

        let handles: Vec<_> = std::mem::take(&mut self.tasks);

        for handle in handles {
            if let Err(e) = handle.await {
                log::error!("Error joining websocket task: {e}");
            }
        }

        self.book_channels.store(AHashMap::new());
        self.book_sync.clear();
        self.option_greeks_subs
            .store(AHashMap::<InstrumentId, AHashSet<OKXGreeksType>>::new());
        self.option_summary_family_subs
            .lock()
            .expect("option_summary_family_subs mutex poisoned")
            .clear();
        self.is_connected.store(false, Ordering::Release);
        Ok(())
    }
}

fn handle_book_sequence_outcome(
    outcome: BookSequenceOutcome,
    instrument_id: InstrumentId,
    book_channels: &Arc<AtomicMap<InstrumentId, OKXBookChannel>>,
    book_sync: &BookSyncTracker,
    recovery_ws: Option<&OKXWebSocketClient>,
    snapshot_timeout: Duration,
    cancel: &CancellationToken,
) -> bool {
    match outcome {
        BookSequenceOutcome::Accept => true,
        BookSequenceOutcome::Suppress => false,

View on GitHub (pinned to d1527c24af)

Solutions

  1. Find and fix the initial panic in the option_summary_family_subs critical section
  2. Reduce the critical section so panicky work happens outside the lock
  3. Handle poisoning gracefully (clear via into_inner) since teardown clearing a possibly-torn map is safe

Example fix

// before
self.option_summary_family_subs.lock().expect("option_summary_family_subs mutex poisoned").clear();
// after
self.option_summary_family_subs.lock().unwrap_or_else(|e| e.into_inner()).clear();
Defensive patterns

Strategy: fallback

Prevention

When it happens

Trigger: connect() or disconnect() calling teardown_transports after any thread panicked while holding option_summary_family_subs — typically a subscribe/unsubscribe path for option summary families that hit a bug between lock and unlock.

Common situations: Rare in practice; usually follows an upstream panic in option subscription handling, after which every reconnect attempt immediately panics, masking the original failure.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@d1527c24af (2026-08-27). Data as JSON: /api/errors/c945d3cd6c04abf0. Report an issue: GitHub.