{"record":{"id":"b029d5f0b42f1e28","repo":"nautechsystems/nautilus_trader","slug":"ib-data-startup-teardown-failed-teardown-error","errorCode":null,"errorMessage":"IB data startup teardown failed: {teardown_error}","messagePattern":"IB data startup teardown failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/interactive_brokers/src/data/core.rs","lineNumber":749,"sourceCode":"        self.ib_client = Some(handle);\n\n        let data_farm_state = Arc::clone(&self.data_farm_state);\n        let cancellation_token = self.cancellation_token.child_token();\n        let clock = self.clock;\n\n        if let Err(e) = self.session_tasks.spawn(async move {\n            if let Err(e) =\n                monitor_data_farm_notices(client, data_farm_state, clock, cancellation_token).await\n            {\n                tracing::warn!(\"IB data farm notice monitor stopped: {e:?}\");\n            }\n        }) {\n            self.session_tasks.begin_shutdown();\n            self.command_tasks.begin_shutdown();\n            self.ib_client = None;\n\n            if let Err(teardown_error) = self.finish_tasks().await {\n                return Err(anyhow::Error::new(e)\n                    .context(format!(\"IB data startup teardown failed: {teardown_error}\")));\n            }\n            return Err(anyhow::Error::new(e).context(\"failed to register IB data farm monitor\"));\n        }\n        self.is_connected.store(true, Ordering::Relaxed);\n\n        let instrument_count = self.instrument_provider.count();\n        if instrument_count > 0 {\n            tracing::debug!(\n                \"Data client connected with {} instruments in provider cache\",\n                instrument_count\n            );\n\n            for instrument in self.instrument_provider.get_all() {\n                if let Err(e) = self.data_sender.send(DataEvent::Instrument(instrument)) {\n                    tracing::warn!(\"Failed to publish startup-loaded instrument: {e}\");\n                    break;\n                }","sourceCodeStart":731,"sourceCodeEnd":767,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/interactive_brokers/src/data/core.rs#L731-L767","documentation":"During InteractiveBrokersDataClient::connect, if the background task that monitors IB data farm notices fails to spawn, the client tears down its session/command task groups and drops the IB client handle. If that teardown (finish_tasks) itself errors, the original spawn error is re-raised with the teardown error appended, so one failure masks another.","triggerScenarios":"connect() succeeds against IB Gateway/TWS but self.session_tasks.spawn(...) returns Err (task-group already shut down or spawn capacity exhausted); then finish_tasks() during rollback also returns Err.","commonSituations":"Calling connect() twice without disconnect(), reusing the client after a prior failed connect left the task groups in a shutdown state, or a client whose runtime was dropped mid-connect.","solutions":["Check the teardown_error in the message to see why task cleanup failed (e.g. runtime already dropped); fix that root cause first.","Ensure connect() is only called once per client instance; create a fresh client after any failed connect.","Call disconnect() before re-connecting so session/command task groups are cleanly re-initialized.","Verify the tokio runtime backing the client is alive and not being shut down while connect() is awaited."],"exampleFix":"// before\nlet client = IBDataClient::new(...); client.connect().await?; client.connect().await?; // second connect fails\n// after\nif !client.is_connected() { client.connect().await?; }","handlingStrategy":"try-catch","validationCode":"// Rust: guard against double-connect / dead runtime\nif client_is_connected { return Ok(()); }\nif tokio::runtime::Handle::try_current().is_err() { return Err(anyhow!(\"no active runtime\")); }","typeGuard":"fn is_connected(client: &IBDataClient) -> bool { client.is_connected() }","tryCatchPattern":"match client.connect().await {\n    Err(e) if e.to_string().contains(\"teardown failed\") => {\n        // inspect chained teardown_error; rebuild a fresh client\n        eprintln!(\"connect failed: {e:#}\");\n    }\n    r => r?,\n}","preventionTips":["Never call connect() twice on the same client instance","Always await disconnect() before reconnecting","Keep the tokio runtime alive for the client's entire lifetime","Log errors with {e:#} to see the full anyhow context chain"],"tags":["rust","interactive-brokers","task-spawn","async"],"backgroundTag":"invalid-state-transition","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}