nautechsystems/nautilus_trader · error · anyhow::Error

Failed to terminate Hyperliquid execution tasks: {e}

Error message

Failed to terminate Hyperliquid execution tasks: {e}

What it means

This error is raised when the Hyperliquid execution client cannot cleanly terminate its pending-task group within the allotted shutdown timeouts during teardown. The TaskGroup's finish_shutdown gives tasks a grace period (1s) plus a hard cancel window (2s) before giving up and returning an error, which is then wrapped with this message.

Source

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

        }

        if let Err(e) = self.await_pending_tasks().await {
            self.shutdown_errors.push(e.to_string());
        }
        self.core.set_disconnected();

        if !self.shutdown_errors.is_empty() {
            anyhow::bail!(std::mem::take(&mut self.shutdown_errors).join("; "));
        }
        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 {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Retry the teardown or client teardown after a short delay so blocked tasks finish or get dropped
  2. Investigate why in-flight tasks hang (network latency, unresponsive Hyperliquid endpoint) and add request timeouts
  3. Check logs from the underlying finish_shutdown error for the specific task that refused to terminate
  4. Increase shutdown grace/cancel durations in the TaskGroup configuration if tasks legitimately need longer

Example fix

// before
self.pending_tasks.finish_shutdown(Duration::from_secs(1), Duration::from_secs(2)).await.map_err(...)?
// after
// on repeated failure, log and force-drop instead of failing teardown:
if let Err(e) = self.pending_tasks.finish_shutdown(Duration::from_secs(1), Duration::from_secs(2)).await {
    log::warn!("Hyperliquid pending tasks did not terminate cleanly: {e}");
}
Defensive patterns

Strategy: try-catch

Validate before calling

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

Try / catch

match client.await_pending_tasks().await { Err(e) => log::warn!("pending tasks did not terminate: {e}; retrying teardown") => retry_teardown(), Ok(_) => {} }

Prevention

When it happens

Trigger: await_pending_tasks() is called from teardown_partial_connect() when a connect attempt fails partway; it errors if any spawned pending tasks (in-flight order submissions/cancellations) are still running after begin_shutdown and fail to finish within the 1s/2s shutdown deadlines.

Common situations: A partially-completed connect where the WebSocket or HTTP side failed but spawned tasks are blocked on slow network I/O; stalled Hyperliquid API calls hanging past the 2s hard-cancel; event-loop congestion delaying task completion.

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