nautechsystems/nautilus_trader · error
Failed to finish Betfair data command tasks: {e}
Error message
Failed to finish Betfair data command tasks: {e} What it means
This error wraps a failure from TaskGroup::finish_shutdown when the Betfair data client tears down its session or command task groups during teardown_partial_connect/finish_tasks. finish_shutdown gives each group a drain window (1s / 2s timeouts); if tasks do not complete or abort cleanly within it, the group returns an error. It means background tokio tasks (session/command handlers) could not be joined or aborted during disconnect.
Source
Thrown at crates/adapters/betfair/src/data.rs:230
where
F: std::future::Future<Output = ()> + Send + 'static,
{
if let Err(e) = self.command_tasks.spawn(future) {
log::warn!("Skipping Betfair data command after shutdown began: {e}");
}
}
async fn finish_tasks(&self) -> anyhow::Result<()> {
let (session_result, command_result) = tokio::join!(
self.session_tasks
.finish_shutdown(Duration::from_secs(1), Duration::from_secs(2)),
self.command_tasks
.finish_shutdown(Duration::from_secs(1), Duration::from_secs(2)),
);
session_result
.map_err(|e| anyhow::anyhow!("Failed to finish Betfair data session tasks: {e}"))?;
command_result
.map_err(|e| anyhow::anyhow!("Failed to finish Betfair data command tasks: {e}"))?;
Ok(())
}
async fn prepare_task_groups(&mut self) -> anyhow::Result<()> {
if !self.session_tasks.is_open() || !self.command_tasks.is_open() {
self.teardown_partial_connect().await?;
self.session_tasks
.start_generation()
.map_err(|e| anyhow::anyhow!("Failed to start Betfair data session tasks: {e}"))?;
self.command_tasks
.start_generation()
.map_err(|e| anyhow::anyhow!("Failed to start Betfair data command tasks: {e}"))?;
}
Ok(())
}
fn begin_stream_shutdown(&self) {
for stream in self.stream_shutdowns.lock().iter() {View on GitHub (pinned to 18893faf8b)
Solutions
- Inspect Betfair session/command task bodies for blocking or long-lived awaits that ignore cancellation and make them cancellation-safe
- Increase the finish_shutdown timeouts (Duration::from_secs(1), Duration::from_secs(2)) if teardown timing is tight in your environment
- Retry teardown_partial_connect after the failed attempt, since finish_tasks errors are recorded in shutdown_errors and teardown still proceeds
- Capture the inner `{e}` value to identify which of the two groups (session vs command) failed and fix that specific task
Example fix
// before self.session_tasks.finish_shutdown(Duration::from_secs(1), Duration::from_secs(2)), // after self.session_tasks.finish_shutdown(Duration::from_secs(5), Duration::from_secs(10))
Defensive patterns
Strategy: try-catch
Validate before calling
// Rust: no pre-validation API; guard with logging on disconnect
if client.is_degraded() {
log::warn!("Betfair data client shutting down with pending tasks; shutdown may time out");
} Try / catch
match client.disconnect().await {
Ok(()) => {},
Err(e) => log::error!("Betfair teardown failed: {e:#}"), // contains 'Failed to finish Betfair data ... tasks'
} Prevention
- Keep Betfair session/command tasks cancellation-safe (use tokio::select! with shutdown signals)
- Avoid long blocking operations in spawned adapter tasks
- Log the inner error to identify which task group hung
- Allow retry of disconnect after a partial teardown
When it happens
Trigger: Called via finish_tasks during teardown_partial_connect (invoked from failed reconnect attempts in prepare_task_groups or disconnect). Triggered when a spawned session or command task hangs past the 1s/2s shutdown timeouts, or when finish_shutdown otherwise returns Err (e.g. task panicked or group already in a bad state).
Common situations: A stuck Betfair stream task blocked on a network read without honoring cancellation; a command task awaiting a response that never arrives; calling disconnect while tasks are mid-flight; reconnect loops where a previous generation left tasks wedged.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
Related errors
- Failed to terminate Hyperliquid data tasks: {e}
- Hyperliquid WebSocket handler did not stop after abort
- Lighter WebSocket handler did not stop after abort
- Polymarket RTDS task shutdown failed: {}
- RTDS connect was canceled by shutdown
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/cdd8f17881a42687.
Report an issue: GitHub.