{"record":{"id":"c945d3cd6c04abf0","repo":"nautechsystems/nautilus_trader","slug":"option-summary-family-subs-mutex-poisoned","errorCode":null,"errorMessage":"option_summary_family_subs mutex poisoned","messagePattern":"option_summary_family_subs mutex poisoned","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/adapters/okx/src/data.rs","lineNumber":1125,"sourceCode":"        if let Some(ref mut ws) = self.ws_business {\n            let _result = ws.close().await;\n        }\n\n        let handles: Vec<_> = std::mem::take(&mut self.tasks);\n\n        for handle in handles {\n            if let Err(e) = handle.await {\n                log::error!(\"Error joining websocket task: {e}\");\n            }\n        }\n\n        self.book_channels.store(AHashMap::new());\n        self.book_sync.clear();\n        self.option_greeks_subs\n            .store(AHashMap::<InstrumentId, AHashSet<OKXGreeksType>>::new());\n        self.option_summary_family_subs\n            .lock()\n            .expect(\"option_summary_family_subs mutex poisoned\")\n            .clear();\n        self.is_connected.store(false, Ordering::Release);\n        Ok(())\n    }\n}\n\nfn handle_book_sequence_outcome(\n    outcome: BookSequenceOutcome,\n    instrument_id: InstrumentId,\n    book_channels: &Arc<AtomicMap<InstrumentId, OKXBookChannel>>,\n    book_sync: &BookSyncTracker,\n    recovery_ws: Option<&OKXWebSocketClient>,\n    snapshot_timeout: Duration,\n    cancel: &CancellationToken,\n) -> bool {\n    match outcome {\n        BookSequenceOutcome::Accept => true,\n        BookSequenceOutcome::Suppress => false,","sourceCodeStart":1107,"sourceCodeEnd":1143,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/d1527c24afdf475115785557f89a55c3e336c51f/crates/adapters/okx/src/data.rs#L1107-L1143","documentation":"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.","triggerScenarios":"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.","commonSituations":"Rare in practice; usually follows an upstream panic in option subscription handling, after which every reconnect attempt immediately panics, masking the original failure.","solutions":["Find and fix the initial panic in the option_summary_family_subs critical section","Reduce the critical section so panicky work happens outside the lock","Handle poisoning gracefully (clear via into_inner) since teardown clearing a possibly-torn map is safe"],"exampleFix":"// before\nself.option_summary_family_subs.lock().expect(\"option_summary_family_subs mutex poisoned\").clear();\n// after\nself.option_summary_family_subs.lock().unwrap_or_else(|e| e.into_inner()).clear();","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep option family subscribe mutations panic-free under the lock","Shrink critical sections to map insert/remove only","Tolerate poison during teardown: clearing is safe even on torn state"],"tags":["rust","mutex-poisoned","okx","options","teardown"],"backgroundTag":"mutex-poisoned","analyzedSha":"d1527c24afdf475115785557f89a55c3e336c51f","analyzedAt":"2026-08-27T04:01:12.327Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}