{"record":{"id":"5ef954b767de23a1","repo":"nautechsystems/nautilus_trader","slug":"client-already-closed","errorCode":null,"errorMessage":"Client already closed","messagePattern":"Client already closed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/databento/src/live.rs","lineNumber":256,"sourceCode":"            }\n        }\n\n        self.send_command(HandlerCommand::Subscribe(sub))\n    }\n\n    /// Starts the live feed handler and returns its message receiver.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the client is already closed, already running, or cannot start.\n    pub fn start(\n        &mut self,\n    ) -> anyhow::Result<(\n        DatabentoFeedHandler,\n        tokio::sync::mpsc::UnboundedReceiver<DatabentoMessage>,\n    )> {\n        if self.is_closed {\n            anyhow::bail!(\"Client already closed\");\n        }\n\n        if self.is_running {\n            anyhow::bail!(\"Client already running\");\n        }\n\n        log::debug!(\"Starting client\");\n\n        let (msg_tx, msg_rx) = tokio::sync::mpsc::unbounded_channel::<DatabentoMessage>();\n        let cmd_rx = self\n            .cmd_rx\n            .take()\n            .ok_or_else(|| anyhow::anyhow!(\"Command receiver already taken\"))?;\n\n        let feed_handler = DatabentoFeedHandler::new(\n            self.credential.clone(),\n            self.dataset.clone(),\n            cmd_rx,","sourceCodeStart":238,"sourceCodeEnd":274,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/databento/src/live.rs#L238-L274","documentation":"The live client's `start` method checks `is_closed` before initializing the feed handler. If the client has already been closed (its `close` was called or close completed), starting is an invalid state transition and the client bails instead of resurrecting a dead client.","triggerScenarios":"Calling `start` (or `py_start`) on a DatabentoLive client after a previous `close()` completed.","commonSituations":"Restarting a strategy/session on the same client object after teardown; reusing a cached client instance across backtests or reconnect logic; calling start twice where the first lifecycle ended in close.","solutions":["Create a new DatabentoLive client instance instead of reusing a closed one.","Track client lifecycle in your orchestration code and only call start on fresh clients.","If reconnection is needed, reconstruct the client with the same credentials and re-subscribe.","Guard the call: skip start if the client reports closed."],"exampleFix":"// before\nclient.close();\nclient.start().await?; // panics/bails: already closed\n// after\nclient.close();\nlet client = DatabentoLive::new(key, dataset, ...)?;\nclient.start().await?;","handlingStrategy":"try-catch","validationCode":"// Skip start if client already terminated\nif client.is_closed() {\n    client = DatabentoLive::new(key, dataset, ...)?;\n}\nclient.start().await?;","typeGuard":null,"tryCatchPattern":"// Rust\nmatch client.start().await {\n    Ok((handler, rx)) => { /* use handler */ }\n    Err(e) if e.to_string().contains(\"already closed\") => {\n        client = DatabentoLive::new(key, dataset, ...)?;\n        client.start().await?;\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Treat clients as single-use: one start, one close","Rebuild client objects on reconnect instead of restarting","Centralize client lifecycle in a session manager"],"tags":["databento","lifecycle","state-transition","live-client"],"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-14T00:17:10.932Z"}