nautechsystems/nautilus_trader · error
Failed to disconnect data clients: {}
Error message
Failed to disconnect data clients: {} What it means
The engine's disconnect method sends disconnect commands to all registered data clients and collects per-client errors. If any client failed to disconnect, it aggregates all error messages (joined with "; ") into a single error. This is a wrapper error — the real causes are in the inner per-client messages.
Source
Thrown at crates/data/src/engine/mod.rs:776
///
/// # 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(DataClientAdapter::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 data clients: {}",
error_msgs.join("; ")
)
}
}
/// Returns `true` if all registered data clients are currently connected.
#[must_use]
pub fn check_connected(&self) -> bool {
self.get_clients()
.iter()
.all(|client| client.is_connected())
}
/// Returns `true` if all registered data clients are currently disconnected.
#[must_use]
pub fn check_disconnected(&self) -> bool {
self.get_clients()View on GitHub (pinned to 18893faf8b)
Solutions
- Parse the joined message after "Failed to disconnect data clients: " and split on "; " to identify which clients failed.
- Fix the root cause per client (check network connectivity, adapter logs, and that clients were connected before disconnect).
- Make disconnect idempotent/tolerant in your shutdown path: log the aggregate error and continue teardown rather than aborting.
Example fix
// before
engine.disconnect()?; // aborts whole shutdown on one bad client
// after
if let Err(e) = engine.disconnect() {
log::warn!("data client disconnect issues: {e}");
} Defensive patterns
Strategy: try-catch
Validate before calling
// Rust
// check client connectivity before disconnecting
let dead: Vec<_> = client_ids.iter().filter(|id| !engine.is_client_connected(id)).collect();
if !dead.is_empty() { log::warn!("clients already disconnected: {dead:?}"); } Try / catch
// Rust
match engine.disconnect() {
Ok(()) => {},
Err(e) => {
let inner = e.to_string();
for msg in inner.strip_prefix("Failed to disconnect data clients: ").unwrap_or(&inner).split("; ") {
log::warn!("disconnect issue: {msg}");
}
}
} Prevention
- Check client connection state before issuing disconnect.
- Treat disconnect errors as non-fatal during shutdown and continue teardown.
- Keep adapter logs alongside the aggregated error to find the failing client quickly.
When it happens
Trigger: Calling DataEngine::disconnect() when one or more underlying data clients return Err from their disconnect (network failures, adapter-side disconnect errors, clients already in a bad state).
Common situations: Shutting down a node where a websocket/adapter connection is already broken; adapter disconnect RPC timing out; multiple adapter failures during teardown causing a long joined error string.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- Failed to disconnect execution clients: {}
- errors joined with "; " (aggregated disconnect errors)
- No client registered with ID {client_id}
- Venue {venue} already routed to {existing_client_id}, cannot
- Cannot subscribe for synthetic instrument `Instrument` data
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/e360439a8a2f3eed.
Report an issue: GitHub.