{"record":{"id":"cdd8f17881a42687","repo":"nautechsystems/nautilus_trader","slug":"failed-to-finish-betfair-data-command-tasks-e","errorCode":null,"errorMessage":"Failed to finish Betfair data command tasks: {e}","messagePattern":"Failed to finish Betfair data command tasks: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/betfair/src/data.rs","lineNumber":230,"sourceCode":"    where\n        F: std::future::Future<Output = ()> + Send + 'static,\n    {\n        if let Err(e) = self.command_tasks.spawn(future) {\n            log::warn!(\"Skipping Betfair data command after shutdown began: {e}\");\n        }\n    }\n\n    async fn finish_tasks(&self) -> anyhow::Result<()> {\n        let (session_result, command_result) = tokio::join!(\n            self.session_tasks\n                .finish_shutdown(Duration::from_secs(1), Duration::from_secs(2)),\n            self.command_tasks\n                .finish_shutdown(Duration::from_secs(1), Duration::from_secs(2)),\n        );\n        session_result\n            .map_err(|e| anyhow::anyhow!(\"Failed to finish Betfair data session tasks: {e}\"))?;\n        command_result\n            .map_err(|e| anyhow::anyhow!(\"Failed to finish Betfair data command tasks: {e}\"))?;\n        Ok(())\n    }\n\n    async fn prepare_task_groups(&mut self) -> anyhow::Result<()> {\n        if !self.session_tasks.is_open() || !self.command_tasks.is_open() {\n            self.teardown_partial_connect().await?;\n            self.session_tasks\n                .start_generation()\n                .map_err(|e| anyhow::anyhow!(\"Failed to start Betfair data session tasks: {e}\"))?;\n            self.command_tasks\n                .start_generation()\n                .map_err(|e| anyhow::anyhow!(\"Failed to start Betfair data command tasks: {e}\"))?;\n        }\n        Ok(())\n    }\n\n    fn begin_stream_shutdown(&self) {\n        for stream in self.stream_shutdowns.lock().iter() {","sourceCodeStart":212,"sourceCodeEnd":248,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/betfair/src/data.rs#L212-L248","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"// before\nself.session_tasks.finish_shutdown(Duration::from_secs(1), Duration::from_secs(2)),\n// after\nself.session_tasks.finish_shutdown(Duration::from_secs(5), Duration::from_secs(10))","handlingStrategy":"try-catch","validationCode":"// Rust: no pre-validation API; guard with logging on disconnect\nif client.is_degraded() {\n    log::warn!(\"Betfair data client shutting down with pending tasks; shutdown may time out\");\n}","typeGuard":null,"tryCatchPattern":"match client.disconnect().await {\n    Ok(()) => {},\n    Err(e) => log::error!(\"Betfair teardown failed: {e:#}\"), // contains 'Failed to finish Betfair data ... tasks'\n}","preventionTips":["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"],"tags":["rust","async","task-shutdown","timeout","shutdown"],"backgroundTag":"request-timeout","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}