nautechsystems/nautilus_trader · error

Failed to disconnect execution clients: {}

Error message

Failed to disconnect execution clients: {}

What it means

The engine's disconnect() calls disconnect on all registered execution clients concurrently and aggregates individual failures. If any client fails to disconnect, it bails with this error containing all per-client error messages joined by '; '.

Source

Thrown at crates/execution/src/engine/mod.rs:669

    ///
    /// # Errors
    ///
    /// Returns an error if any client fails to disconnect.
    pub async fn disconnect(&mut self) -> anyhow::Result<()> {
        let futures: Vec<_> = self
            .get_clients_mut()
            .into_iter()
            .map(ExecutionClientAdapter::disconnect)
            .collect();

        let results = join_all(futures).await;
        let errors: Vec<_> = results.into_iter().filter_map(Result::err).collect();

        if errors.is_empty() {
            Ok(())
        } else {
            let error_msgs: Vec<_> = errors.iter().map(ToString::to_string).collect();
            anyhow::bail!(
                "Failed to disconnect execution clients: {}",
                error_msgs.join("; ")
            )
        }
    }

    /// Sets the `manage_own_order_books` configuration option.
    pub fn set_manage_own_order_books(&mut self, value: bool) {
        self.config.manage_own_order_books = value;
    }

    /// Starts the position snapshot timer if configured.
    #[expect(
        clippy::missing_panics_doc,
        reason = "timer registration is not expected to fail"
    )]
    pub fn start_snapshot_timer(&mut self) {
        if let Some(interval_secs) = self

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Read the joined per-client messages in the error to identify which clients failed and why.
  2. For transient network causes, retry disconnect() — it is safe to call during shutdown as long as clients are still registered.
  3. Fix the underlying client disconnect implementation if the failure is deterministic (adapter bug).
  4. If shutdown must proceed regardless, tolerate/log this error: failing to disconnect at process exit typically doesn't require aborting the shutdown.
  5. Ensure clients are connected before disconnecting; check connection state handling in the adapter.

Example fix

// before
engine.disconnect().await?; // aborts shutdown on one bad client
// after
if let Err(e) = engine.disconnect().await {
    log::warn!("disconnect failures during shutdown: {e}");
}
Defensive patterns

Strategy: try-catch

Try / catch

match engine.disconnect().await {
    Err(e) if e.to_string().starts_with("Failed to disconnect execution clients") => {
        log::warn!("non-fatal disconnect failures: {e}"); // proceed with shutdown
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling ExecutionEngine::disconnect() when one or more execution clients' disconnect() implementations return Err — e.g. network failures while closing exchange connections, or adapter-specific cleanup errors.

Common situations: Shutting down a node while a venue connection is already broken or the WebSocket close handshake times out; a fault-injected or stale adapter failing cleanup; live client to an unreachable exchange during shutdown.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


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