nautechsystems/nautilus_trader · error · anyhow::Error

{shutdown_errors joined with "; "}

Error message

{shutdown_errors joined with "; "}

What it means

During HyperliquidDataClient teardown (teardown_partial_connect), any errors from shutting down individual streams/tasks are accumulated in shutdown_errors. If any were collected, teardown fails and the joined messages are surfaced as a single bail! describing every component-level shutdown problem encountered.

Source

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

        self.abort_pending_tasks();

        if let Err(e) = self.ws_client.disconnect().await {
            self.shutdown_errors
                .push(format!("Hyperliquid WebSocket shutdown failed: {e}"));
        }

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

        if let Err(e) = self.await_pending_tasks().await {
            self.shutdown_errors.push(e.to_string());
        }
        self.clear_stream_health();
        self.is_connected.store(false, Ordering::Release);

        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 data 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

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Read the joined messages to identify the failing component, then fix the root cause (e.g. network reachability of Hyperliquid WS endpoints).
  2. Retry the connect/disconnect operation after ensuring no stale client state; reconnect cleanly.
  3. Check logs for the individual per-component errors that were pushed into shutdown_errors during teardown.
Defensive patterns

Strategy: try-catch

Try / catch

match client.connect().await {
    Err(e) if e.to_string().contains(';') => {
        tracing::warn!("partial shutdown errors: {e}");
        // inspect per-component logs, then retry connect
    }
    r => r?,
}

Prevention

When it happens

Trigger: Calling connect() or disconnect() when one or more underlying WebSocket streams or spawned tasks fail to shut down cleanly — e.g. a ws client close errors, a task join fails, or clear/register stream health cleanup errors during teardown.

Common situations: Network interruptions at disconnect time; attempting to connect after a previous partial failure left stale resources; abrupt venue-side disconnections causing task panics that surface during teardown.

Related errors


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