nautechsystems/nautilus_trader · warning
Failed to finish Betfair data session tasks: {e}
Error message
Failed to finish Betfair data session tasks: {e} What it means
During Betfair data-client teardown, finish_tasks awaits both session and command task groups' finish_shutdown and maps any error in the session group to this message. It means session-related spawned tasks did not shut down cleanly within the 1s/2s grace timeouts.
Source
Thrown at crates/adapters/betfair/src/data.rs:228
fn spawn_command<F>(&self, future: F)
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(())
}
View on GitHub (pinned to 18893faf8b)
Solutions
- Check the wrapped {e} for whether tasks timed out or panicked
- Ensure the stream socket is properly closed/aborted before finish_shutdown so session tasks can exit
- Log and continue if this occurs during partial-teardown cleanup, since the client is being discarded anyway
- Increase shutdown budgets if the network legitimately needs longer to drain
Example fix
// before session_tasks.finish_shutdown(Duration::from_secs(1), Duration::from_secs(2)) // after (if slow networks are expected) session_tasks.finish_shutdown(Duration::from_secs(5), Duration::from_secs(10))
Defensive patterns
Strategy: try-catch
Try / catch
// Rust
if let Err(e) = finish_tasks().await {
// teardown path: log, don't mask the original disconnect error
tracing::warn!("betfair session tasks shutdown incomplete: {e:#}");
} Prevention
- Abort/cancel stream sockets before finish_shutdown so session tasks can exit promptly
- Keep shutdown grace periods larger than your worst-case network stall
- Avoid panics in session task bodies (validate stream data defensively)
- Treat teardown errors as warnings during partial-connect cleanup
When it happens
Trigger: Calling teardown_partial_connect -> finish_tasks when session tasks are hung, panicked, or fail to complete within Duration::from_secs(1)/from_secs(2) deadlines.
Common situations: Session tasks blocked on a stalled Betfair stream socket during disconnect; task panics from bad stream data; slow network keeping reads pending past the shutdown timeout.
Related errors
- Failed to finish Coinbase poll tasks: {e}
- Failed to terminate Coinbase execution tasks: {e}
- Failed to terminate Coinbase session tasks: {e}
- Betfair data shutdown failed: {}
- Betfair execution shutdown failed: {}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/515aa9edbf0da033.
Report an issue: GitHub.