nautechsystems/nautilus_trader · error · anyhow::Error

Failed to terminate Hyperliquid execution session tasks: {e}

Error message

Failed to terminate Hyperliquid execution session tasks: {e}

What it means

Raised when the Hyperliquid execution client's session-task group (long-lived WebSocket/session loops) cannot be terminated within the shutdown grace and cancel windows during teardown. It wraps the underlying finish_shutdown error from the TaskGroup.

Source

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

        Ok(())
    }

    async fn await_pending_tasks(&self) -> anyhow::Result<()> {
        self.pending_tasks.begin_shutdown();
        self.pending_tasks
            .finish_shutdown(Duration::from_secs(1), Duration::from_secs(2))
            .await
            .map_err(|e| anyhow::anyhow!("Failed to terminate Hyperliquid execution tasks: {e}"))?;
        Ok(())
    }

    async fn await_session_tasks(&self) -> anyhow::Result<()> {
        self.session_tasks.begin_shutdown();
        self.session_tasks
            .finish_shutdown(Duration::from_secs(1), Duration::from_secs(2))
            .await
            .map_err(|e| {
                anyhow::anyhow!("Failed to terminate Hyperliquid execution session tasks: {e}")
            })?;
        Ok(())
    }
}

#[async_trait(?Send)]
impl ExecutionClient for HyperliquidExecutionClient {
    fn is_connected(&self) -> bool {
        self.core.is_connected()
    }

    fn client_id(&self) -> ClientId {
        self.core.client_id
    }

    fn account_id(&self) -> AccountId {
        self.core.account_id
    }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check that session tasks honor the begin_shutdown signal promptly in their select loops
  2. Retry teardown after a delay, or treat it as non-fatal and log a warning
  3. Inspect the wrapped error to identify which session task stalled
  4. Increase the grace/cancel durations if session loops legitimately need longer to unwind

Example fix

// before
.map_err(|e| anyhow::anyhow!("Failed to terminate Hyperliquid execution session tasks: {e}"))?;
// after
if let Err(e) = self.session_tasks.finish_shutdown(Duration::from_secs(1), Duration::from_secs(2)).await {
    log::warn!("session tasks did not terminate cleanly: {e}");
}
Defensive patterns

Strategy: try-catch

Validate before calling

if !self.session_tasks.is_open() { self.teardown_partial_connect().await?; }

Try / catch

match client.await_session_tasks().await { Err(e) => { log::warn!("session tasks did not terminate: {e}"); /* proceed or retry */ } Ok(_) => {} }

Prevention

When it happens

Trigger: await_session_tasks() is called from teardown_partial_connect() after a failed/partial connect; it errors when session tasks do not stop within Duration::from_secs(1) grace plus Duration::from_secs(2) hard-cancel.

Common situations: A session task blocked awaiting a WebSocket read that ignores the shutdown signal; slow network teardown after a partial connect failure; a session task stuck retrying against an unreachable Hyperliquid endpoint.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/cb3dd4868585029c. Report an issue: GitHub.