nautechsystems/nautilus_trader · error · anyhow::Error

Failed to start Hyperliquid data session generation

Error message

Failed to start Hyperliquid data session generation: {e}

What it means

Raised in `connect` when, after aborting pending work and awaiting old session/pending tasks, `session_tasks.start_generation()` fails. The task manager refuses to begin a new generation of WebSocket session tasks (e.g. it is not in a state where a new generation can start, or prior generation bookkeeping is inconsistent). Connection cannot proceed, so the connect attempt fails with this message.

Solutions

  1. Retry connect once after the previous teardown has fully completed (await the disconnect).
  2. Avoid calling connect concurrently; serialize connection lifecycle on one task/lock.
  3. If persistent, recreate the data client instance to get a fresh task manager.
  4. Report/upgrade if a clean sequence (disconnect then connect) still fails repeatedly.

Example fix

// before
tokio::join!(client.connect(), client.connect()); // racing connects
// after
disconnect_handle.await; // ensure prior teardown finished
client.connect().await?;
Defensive patterns

Strategy: try-catch

Try / catch

// ensure serialized lifecycle and treat as transient
match client.connect().await {
    Err(e) if e.to_string().contains("session generation") => {
        tokio::time::sleep(Duration::from_millis(500)).await;
        client.connect().await?; // one retry after teardown settles
    }
    r => r?,
}

Prevention

When it happens

Trigger: Calling connect on the Hyperliquid data client when the internal session task manager rejects `start_generation` — typically after a previous shutdown did not fully reset the task registry or a concurrent connect/teardown raced.

Common situations: Rapid connect/disconnect cycles; concurrent connect calls from multiple threads/tasks on the same client; a prior error[3100]-style shutdown timeout leaving the manager in a dirty state.

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

Appendix: source

Thrown at crates/adapters/hyperliquid/src/data.rs:640

        {
            // `reset()` is synchronous, while shutting down the inner socket
            // is async. Complete that teardown before creating any new stream
            // task so its receiver and subscription registries cannot belong
            // to the previous generation.
            self.ws_client.begin_shutdown();
            self.ws_client
                .disconnect()
                .await
                .context("failed to tear down Hyperliquid WebSocket before reconnect")?;
            self.ws_client.reset_runtime_state();
            self.abort_session_tasks();
            self.abort_pending_tasks();
            let (session_result, pending_result) =
                tokio::join!(self.await_session_tasks(), self.await_pending_tasks());
            session_result?;
            pending_result?;
            self.session_tasks.start_generation().map_err(|e| {
                anyhow::anyhow!("Failed to start Hyperliquid data session generation: {e}")
            })?;
            self.pending_tasks.start_generation().map_err(|e| {
                anyhow::anyhow!("Failed to start Hyperliquid data task generation: {e}")
            })?;
            self.cancellation_token = CancellationToken::new();
        }
        let cancellation_token = self.cancellation_token.clone();
        let ws_client = self.ws_client.clone();
        let setup_guard =
            TaskGroupGuard::new(&[&self.session_tasks, &self.pending_tasks], move || {
                cancellation_token.cancel();
                ws_client.begin_shutdown();
            });

        register_hyperliquid_custom_data();

        let instruments = self
            .bootstrap_instruments()

View on GitHub (pinned to 18893faf8b)