nautechsystems/nautilus_trader · error · anyhow::Error

Failed to start Hyperliquid data task generation: {e}

Error message

Failed to start Hyperliquid data task generation: {e}

What it means

Same connect sequence as error 3102 but for the `pending_tasks` manager: `pending_tasks.start_generation()` failed while starting a new generation of background (pending) data tasks. Connect aborts with this error after the session generation already started, leaving the client not fully connected.

Source

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

            // 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()
            .await
            .context("failed to bootstrap instruments")?;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure full teardown before reconnecting (await disconnect to completion).
  2. Serialize the connect/disconnect lifecycle; never interleave them.
  3. Recreate the data client if the task manager remains in a bad state.
  4. Check logs for the earlier pending-task shutdown error that left the stale state.

Example fix

// before
let _ = client.disconnect().await; // ignoring incomplete teardown
client.connect().await?;
// after
client.disconnect().await?; // propagate teardown errors first
client.connect().await?;
Defensive patterns

Strategy: try-catch

Try / catch

// serialize lifecycle; on pending-generation failure, tear down and retry once
if let Err(e) = client.connect().await {
    if e.to_string().contains("task generation") {
        let _ = client.disconnect().await;
        tokio::time::sleep(Duration::from_millis(500)).await;
        client.connect().await?;
    } else {
        return Err(e);
    }
}

Prevention

When it happens

Trigger: Calling connect when the pending-task registry cannot start a new generation — stale generation state from an incomplete previous shutdown, or concurrent connect/teardown racing on the same client.

Common situations: Rapid reconnect loops in a supervisor; calling connect while a previous disconnect's `await_pending_tasks` was still timing out; sharing one client across tasks.

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