nautechsystems/nautilus_trader · error
errors joined with "; " (aggregated disconnect errors)
Error message
errors joined with "; " (aggregated disconnect errors)
What it means
During disconnect or a failed partial connect, the Deribit adapter tears down session and pending tokio tasks and collects any error each teardown step produced. Instead of failing on the first error, it aggregates all of them and returns a single anyhow error with the messages joined by "; ". This means the connection teardown hit one or more problems (e.g. tasks failed to shut down cleanly, channel sends failed), all of which are reported at once.
Source
Thrown at crates/adapters/deribit/src/data.rs:263
}
let mut errors = Vec::new();
if let Some(ws) = self.ws_client.as_ref()
&& let Err(e) = ws.close().await
{
errors.push(format!("WebSocket shutdown failed: {e}"));
}
if let Err(e) = self.finish_tasks().await {
errors.push(e.to_string());
}
self.is_connected.store(false, Ordering::Release);
if errors.is_empty() {
Ok(())
} else {
anyhow::bail!(errors.join("; "))
}
}
/// Gets the interval from params, defaulting to Raw if authenticated.
///
/// If authenticated, we prefer Raw interval for best data quality.
/// Users can still override via params if they want 100ms or agg2.
fn get_interval(&self, params: &Option<Params>) -> Option<DeribitUpdateInterval> {
if let Some(interval) = params
.as_ref()
.and_then(|p| p.get_str("interval"))
.and_then(|s| s.parse::<DeribitUpdateInterval>().ok())
{
return Some(interval);
}
// Default to Raw if authenticated, otherwise None (100ms default)
if let Some(ws) = self.ws_client.as_ref()View on GitHub (pinned to 18893faf8b)
Solutions
- Read the joined messages to identify which sub-step(s) failed; each segment names one underlying cause
- Check network/WS connectivity to Deribit and retry the disconnect once tasks have settled
- Ensure you do not double-disconnect or drop the client while requests are in flight
- If a task hangs, inspect session_tasks/pending_tasks shutdown paths (TaskGroupGuard) for blocking joins and consider a shutdown timeout
Example fix
// before: blindly retrying connect after failed teardown
client.connect().await?;
// after: surface and log each aggregated cause before reconnecting
if let Err(e) = client.disconnect().await {
for cause in e.to_string().split("; ") {
tracing::warn!(cause, "teardown error");
}
}
client.connect().await?; Defensive patterns
Strategy: try-catch
Validate before calling
// Ensure clean state before teardown assert!(!client.is_connected(), "already disconnected");
Try / catch
match client.disconnect().await {
Err(e) => e.to_string().split("; ").for_each(|c| log::warn!("teardown: {c}")),
Ok(()) => {},
} Prevention
- Don't drop the client while requests are in flight
- Avoid double-disconnect; track connection state
- Ensure network reachability before disconnect so shutdown signaling succeeds
When it happens
Trigger: Calling client.disconnect(), or connect() when the WebSocket/HTTP setup partially fails, causes teardown_partial_connect to run; if any spawned task join or shutdown step errors, the errors vec is non-empty and bail!(errors.join("; ")) fires.
Common situations: Network drop mid-session so the WS task already died and shutdown signals fail; calling disconnect twice or disconnecting while tasks are stuck waiting on the remote; cancel-safe shutdown of pending order tasks that never received a response.
Related errors
- errors joined with "; " (aggregated disconnect errors)
- InstrumentState channel requires kind and currency parameter
- Binance Spot data teardown failed: {}
- std::mem::take(&mut self.shutdown_errors).join("; ")
- Unsupported Deribit resolution: {resolution}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/15099be29c0048c0.
Report an issue: GitHub.