nautechsystems/nautilus_trader · error · anyhow::Error

Failed to start Hyperliquid task generation: {e}

Error message

Failed to start Hyperliquid task generation: {e}

What it means

Raised in connect() when start_generation() on the pending-tasks TaskGroup fails, meaning a new task generation could not be opened because the group is not in a state admitting new tasks (e.g. it is still shutting down from a previous generation). Before retrying, the client tears down any partial connect.

Source

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

            Ok(())
        });

        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}"
                )));

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Wait for the previous generation to fully shut down before reconnecting (add a delay/backoff between connect attempts)
  2. Ensure the prior teardown completes without error and logs are clean before retrying connect
  3. Investigate why previous-generation tasks did not terminate (see 3110)
  4. Inspect the wrapped TaskGroup error for the precise state violation

Example fix

null
Defensive patterns

Strategy: retry

Validate before calling

assert!(client.pending_tasks.is_open() || previous_teardown_completed);

Try / catch

loop { match client.connect().await { Ok(_) => break, Err(e) if e.to_string().contains("task generation") => { sleep(backoff).await; } Err(e) => return Err(e) } }

Prevention

When it happens

Trigger: connect() sees either pending_tasks or session_tasks not open, calls teardown_partial_connect(), then attempts pending_tasks.start_generation(); failure occurs when the prior generation's tasks have not fully terminated, leaving the group closed.

Common situations: Rapid reconnect cycles where the previous generation's tasks are still unwinding; a prior teardown that failed with the 'Failed to terminate Hyperliquid execution tasks' error leaving the group in a shutdown 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/94595d73e4286e81. Report an issue: GitHub.