nautechsystems/nautilus_trader · error · anyhow::Error
{shutdown_errors joined with "; "}
Error message
{shutdown_errors joined with "; "} What it means
During teardown (partial-connect cleanup or disconnect), the client shuts down background tasks and collects any failures into shutdown_errors. If any teardown step failed, the accumulated messages are joined with "; " and returned as a single aggregated error.
Source
Thrown at crates/adapters/hyperliquid/src/execution.rs:634
self.begin_session_shutdown();
self.pending_tasks.begin_shutdown();
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.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))
.awaitView on GitHub (pinned to 18893faf8b)
Solutions
- Read the joined message to identify which specific shutdown step(s) failed and address those underlying errors first.
- Retry disconnect() — shutdown_errors is taken (cleared) on this error, so a fresh attempt starts clean.
- Ensure tasks are cancelled and data streams are closed before dropping the client (unsubscribe/cancel outstanding requests).
- Upgrade the adapter if the underlying failure looks like a teardown race/bug.
Defensive patterns
Strategy: try-catch
Try / catch
if let Err(e) = client.disconnect().await {
log::error!("disconnect reported shutdown failures: {e}");
// retry once; shutdown_errors was cleared by the failed attempt
client.disconnect().await?;
} Prevention
- Cancel outstanding tasks/subscriptions before disconnecting
- Ensure clean network state (no in-flight requests) at teardown
- Log the joined message to identify the failing shutdown step
When it happens
Trigger: Calling disconnect (or failing a connect and running teardown_partial_connect) while one or more shutdown steps fail — e.g. await_pending_tasks reports a task error, WebSocket close fails, or command-sender shutdown fails; all messages are joined and raised together.
Common situations: Disconnecting while subscriptions/tasks are still in flight and erroring during cancellation; a partially initialized client being torn down after a failed connect; network errors during WebSocket close.
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
- Failed to terminate Hyperliquid data tasks: {e}
- Failed to terminate Hyperliquid execution tasks: {e}
- option_summary_family_subs mutex poisoned
- Unsupported OrderType for conditional orders: {value:?}
- Close command should not be drained
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/3b9697946728c419.
Report an issue: GitHub.