nautechsystems/nautilus_trader · error · anyhow::Error

Failed to start Hyperliquid execution session generation: {e

Error message

Failed to start Hyperliquid execution session generation: {e}

What it means

Raised in connect() when start_generation() on the session-tasks TaskGroup fails, meaning a new generation of long-lived session tasks (e.g. the WebSocket stream session) could not be started. This happens immediately after the pending-tasks generation started successfully, so the connect fails as a whole.

Source

Thrown at crates/adapters/hyperliquid/src/execution.rs:1692

        Ok(())
    }

    async fn connect(&mut self) -> anyhow::Result<()> {
        if self.core.is_connected() && self.pending_tasks.is_open() && self.session_tasks.is_open()
        {
            return Ok(());
        }

        log::info!("Connecting Hyperliquid execution client");

        if !self.pending_tasks.is_open() || !self.session_tasks.is_open() {
            self.teardown_partial_connect().await?;
            self.pending_tasks
                .start_generation()
                .map_err(|e| anyhow::anyhow!("Failed to start Hyperliquid task generation: {e}"))?;
            self.session_tasks.start_generation().map_err(|e| {
                anyhow::anyhow!("Failed to start Hyperliquid execution session generation: {e}")
            })?;
        }
        let ws_client = self.ws_client.clone();
        let setup_guard =
            TaskGroupGuard::new(&[&self.session_tasks, &self.pending_tasks], move || {
                ws_client.begin_shutdown();
            });

        self.ensure_instruments_initialized_async().await?;
        let ready_bracket_parents = self.restore_staged_brackets();

        if let Err(e) = self.start_ws_stream().await {
            if let Err(teardown_error) = self.teardown_partial_connect().await {
                return Err(e.context(format!(
                    "Hyperliquid execution startup teardown failed: {teardown_error}"
                )));
            }
            return Err(e);

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Add backoff before retrying connect so the session group fully resets
  2. Verify the previous session generation terminated (check for 'Failed to terminate ... session tasks' errors in logs)
  3. Investigate the wrapped TaskGroup error for the exact state problem
  4. Restart the node/client if the group remains stuck closed

Example fix

null
Defensive patterns

Strategy: retry

Validate before calling

assert!(client.session_tasks.is_open());

Try / catch

if let Err(e) = client.connect().await { if e.to_string().contains("session generation") { sleep(backoff).await; retry(); } }

Prevention

When it happens

Trigger: connect() calls session_tasks.start_generation() after pending_tasks.start_generation() succeeded; failure occurs if the session group is still closed/shutting down from a previous generation despite teardown_partial_connect().

Common situations: Back-to-back reconnects outpacing session-task shutdown; a leaked session task from an earlier failed connect keeping the group closed; event-loop starvation delaying generation setup.

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