nautechsystems/nautilus_trader · error

failed to stop prior WebSocket handler: {e}

Error message

failed to stop prior WebSocket handler: {e}

What it means

In the Deribit WebSocket client's `connect`, any leftover handler tasks from a previous connection are shut down via `finish_handler()`. This error wraps the underlying failure of that shutdown, preventing a clean reconnect. It signals the internal task-generation manager could not be transitioned into shutdown.

Source

Thrown at crates/adapters/deribit/src/websocket/client.rs:535

    /// # Errors
    ///
    /// Returns an error if the connection fails.
    pub async fn connect(&mut self) -> anyhow::Result<()> {
        let connect_lock = Arc::clone(&self.connect_lock);
        let _connect_guard = connect_lock.lock().await;

        log_debug!(
            "Connecting to WebSocket: {}",
            self.url,
            color = LogColor::Blue
        );

        if !self.handler_tasks.is_open() || !self.handler_tasks.is_empty() {
            self.handler_tasks.begin_shutdown();
            self.signal.store(true, Ordering::Relaxed);
            self.finish_handler()
                .await
                .map_err(|e| anyhow::anyhow!("failed to stop prior WebSocket handler: {e}"))?;
            self.handler_tasks.start_generation().map_err(|e| {
                anyhow::anyhow!("failed to start WebSocket handler task generation: {e}")
            })?;
        }
        let handler_spawner = self.handler_tasks.spawner().map_err(|e| {
            anyhow::anyhow!("failed to acquire WebSocket handler task spawner: {e}")
        })?;

        // Reset stop signal and subscription state so callers can
        // resubscribe cleanly after a manual disconnect/connect cycle.
        self.signal.store(false, Ordering::Relaxed);
        self.subscriptions_state.clear();

        // Create message handler and channel
        let (message_handler, raw_rx) = channel_message_handler();

        // No-op ping handler: handler responds to pings directly
        // Inbound Ping frames are answered by the transport, so no ping handler is needed;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Log the inner error `{e}` to see why finish_handler failed (hung task vs runtime issue).
  2. Ensure the prior session was properly disconnected before calling connect again.
  3. Check for concurrent connect()/disconnect() calls and serialize them with a lock.
  4. If the handler task is stuck, add timeouts around the blocking part of the handler loop so shutdown can complete.
  5. Upgrade/inspect the TaskGroup (handler_tasks) implementation if errors persist on a fresh client.

Example fix

// before
let _ = client.connect().await;
// after
client.disconnect().await?; // ensure prior handler fully stopped
let _ = client.connect().await?;
Defensive patterns

Strategy: try-catch

Validate before calling

// Rust
if client.handler_state_unclean() /* or track your own connected flag */ {
    client.disconnect().await?;
}

Try / catch

match client.connect().await {
    Err(e) if e.to_string().contains("failed to stop prior WebSocket handler") => {
        // rebuild client or retry after backoff
    }
    Ok(v) => v,
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling `connect()` while `handler_tasks` is open or non-empty (a prior session's handler still exists) and the task group's shutdown/generation handshake fails (e.g. handler task hung, generation state corrupted, runtime shutdown in progress).

Common situations: Reconnecting after an unclean disconnect where the old message-handler task never completed; calling connect concurrently from two places; tearing down the tokio runtime while the handler is still draining; a bug in TaskGroup's generation lifecycle.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/169949ad22dd2664. Report an issue: GitHub.