{"record":{"id":"d45fe2a53a16ed27","repo":"nautechsystems/nautilus_trader","slug":"slots-lock-poisoned","errorCode":null,"errorMessage":"slots lock poisoned","messagePattern":"slots lock poisoned","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/adapters/dydx/src/websocket/client.rs","lineNumber":587,"sourceCode":"        if self.is_connected() {\n            return Ok(());\n        }\n\n        self.signal.store(false, Ordering::Release);\n\n        let (out_tx, out_rx) = tokio::sync::mpsc::unbounded_channel::<DydxWsOutputMessage>();\n        {\n            let mut guard = self.out_tx.lock().expect(\"out_tx lock poisoned\");\n            *guard = Some(out_tx);\n        }\n        {\n            let mut guard = self.out_rx.lock().expect(\"out_rx lock poisoned\");\n            *guard = Some(out_rx);\n        }\n\n        let slot = self.create_connection(0).await?;\n        self.connection_mode.store(slot.connection_mode.clone());\n        self.slots.lock().expect(\"slots lock poisoned\").push(slot);\n\n        log::debug!(\"Connected dYdX WebSocket pool: {}\", self.url);\n        Ok(())\n    }\n\n    /// Disconnects all websocket connections in the pool.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the underlying clients cannot be accessed.\n    #[expect(clippy::missing_panics_doc, reason = \"mutex poisoning is not expected\")]\n    pub async fn disconnect(&mut self) -> DydxWsResult<()> {\n        self.signal.store(true, Ordering::Release);\n\n        let slots: Vec<ConnectionSlot> = {\n            let mut guard = self.slots.lock().expect(\"slots lock poisoned\");\n            guard.drain(..).collect()\n        };","sourceCodeStart":569,"sourceCodeEnd":605,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/d1527c24afdf475115785557f89a55c3e336c51f/crates/adapters/dydx/src/websocket/client.rs#L569-L605","documentation":"The dYdX websocket pool's connect() panicked because the internal Mutex guarding connection slots is poisoned — another thread panicked while holding that lock (the .expect on lock() then fails).","triggerScenarios":"A prior operation holding self.slots (or self.out_rx) panicked, poisoning the mutex; any subsequent connect() call panics with 'slots lock poisoned'.","commonSituations":"An earlier bug or unwind (e.g. a failed .expect inside a lock scope) poisoned the lock during a disconnect or subscribe path; all later pool operations then panic.","solutions":["Find the original panic in earlier logs — this error is a symptom, not the cause","Report the underlying panic if it originates inside the adapter; avoid reusing the client after a poisoned lock","Recreate the dYdX WebSocket client/pool instance to recover","Upgrade the crate: lock poisoning here usually indicates a fixed-or-fixable upstream bug"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// Rust: probe lock health before reconnecting\nif client.slots_lock_poisoned() { client = DydxWebSocketClient::new(...).await?; }","typeGuard":"fn client_usable(client: &DyxWebSocketClient) -> bool {\n    !client.locks_poisoned()\n}","tryCatchPattern":"// catch_unwind around connect; recreate client on poisoning\nlet r = std::panic::catch_unwind(|| client.connect());\nif r.is_err() { let client = rebuild_client().await?; }","preventionTips":["Never reuse a client after any panic on its internals","Report the first panic in logs — poisoning is only a symptom","Wrap adapter connect in supervision that rebuilds the client on panic"],"tags":["dydx","websocket","mutex","panic","lock-poisoned"],"backgroundTag":"mutex-poisoned","analyzedSha":"d1527c24afdf475115785557f89a55c3e336c51f","analyzedAt":"2026-08-27T04:01:12.327Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}