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

  1. Find the original panic in earlier logs — this error is a symptom, not the cause
  2. Report the underlying panic if it originates inside the adapter; avoid reusing the client after a poisoned lock
  3. Recreate the dYdX WebSocket client/pool instance to recover
  4. 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

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


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