nautechsystems/nautilus_trader · critical
slots lock poisoned
Error message
slots lock poisoned
What it means
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).
Source
Thrown at crates/adapters/dydx/src/websocket/client.rs:587
if self.is_connected() {
return Ok(());
}
self.signal.store(false, Ordering::Release);
let (out_tx, out_rx) = tokio::sync::mpsc::unbounded_channel::<DydxWsOutputMessage>();
{
let mut guard = self.out_tx.lock().expect("out_tx lock poisoned");
*guard = Some(out_tx);
}
{
let mut guard = self.out_rx.lock().expect("out_rx lock poisoned");
*guard = Some(out_rx);
}
let slot = self.create_connection(0).await?;
self.connection_mode.store(slot.connection_mode.clone());
self.slots.lock().expect("slots lock poisoned").push(slot);
log::debug!("Connected dYdX WebSocket pool: {}", self.url);
Ok(())
}
/// Disconnects all websocket connections in the pool.
///
/// # Errors
///
/// Returns an error if the underlying clients cannot be accessed.
#[expect(clippy::missing_panics_doc, reason = "mutex poisoning is not expected")]
pub async fn disconnect(&mut self) -> DydxWsResult<()> {
self.signal.store(true, Ordering::Release);
let slots: Vec<ConnectionSlot> = {
let mut guard = self.slots.lock().expect("slots lock poisoned");
guard.drain(..).collect()
};View on GitHub (pinned to d1527c24af)
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
Defensive patterns
Strategy: fallback
Validate before calling
// Rust: probe lock health before reconnecting
if client.slots_lock_poisoned() { client = DydxWebSocketClient::new(...).await?; } Type guard
fn client_usable(client: &DyxWebSocketClient) -> bool {
!client.locks_poisoned()
} Try / catch
// catch_unwind around connect; recreate client on poisoning
let r = std::panic::catch_unwind(|| client.connect());
if r.is_err() { let client = rebuild_client().await?; } Prevention
- 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
When it happens
Trigger: A prior operation holding self.slots (or self.out_rx) panicked, poisoning the mutex; any subsequent connect() call panics with 'slots lock poisoned'.
Common situations: 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.
Related errors
- in-flight mutex poisoned
- wallet balance mutex poisoned
- OCM state lock poisoned
- InstrumentState channel requires kind and currency parameter
- No instrument cached for clob_pair_id {clob_pair_id}
AI-assisted analysis of nautechsystems/nautilus_trader@d1527c24af (2026-08-27).
Data as JSON: /api/errors/d45fe2a53a16ed27.
Report an issue: GitHub.