nautechsystems/nautilus_trader · error

failed to start WebSocket handler task generation: {e}

Error message

failed to start WebSocket handler task generation: {e}

What it means

After stopping prior handler tasks during `connect()`, the client advances `handler_tasks` to a new generation via `start_generation()`. This error wraps a failure of that generation rollover, meaning the client cannot prepare a fresh task-generation for the new WebSocket session.

Source

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

    /// 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;
        // the reader routes them away from the message channel and the handler never sees them.

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the wrapped `{e}` from start_generation for the specific generation-state reason.
  2. Wait for full teardown of the previous session (await disconnect) before reconnecting.
  3. Serialize connect calls; add a mutex/actor around connect/disconnect.
  4. If the task group was permanently shut down, rebuild a new client instance instead of reconnecting.
  5. File/inspect TaskGroup logic if start_generation fails on a fresh open group.

Example fix

// before
client.connect().await?; // may race old generation teardown
// after
tokio::time::sleep(Duration::from_millis(100)).await; // or await disconnect completion
client.connect().await?;
Defensive patterns

Strategy: try-catch

Validate before calling

// Track session lifecycle yourself; only connect when fully disconnected.
assert!(client.is_disconnected());

Try / catch

if let Err(e) = client.connect().await {
    if e.to_string().contains("handler task generation") {
        tokio::time::sleep(RECONNECT_DELAY).await;
        client = rebuild_client().await?;
    }
}

Prevention

When it happens

Trigger: Calling `connect()` after prior handlers exist and `handler_tasks.start_generation()` returns an Err — e.g. the generation manager still considers a prior generation active, or it was shut down and cannot restart.

Common situations: Rapid disconnect/reconnect cycles racing the previous generation's teardown; a prior `finish_handler()` that only partially completed; shutting down the task group while a reconnect is in flight.

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/d883ebf34b565fd0. Report an issue: GitHub.