{"record":{"id":"b4ca9fd93af35f02","repo":"nautechsystems/nautilus_trader","slug":"cannot-connect-while-previous-websocket-handler-ta","errorCode":null,"errorMessage":"Cannot connect while previous WebSocket handler task is still running","messagePattern":"Cannot connect while previous WebSocket handler task is still running","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/okx/src/websocket/client.rs","lineNumber":600,"sourceCode":"    }\n\n    /// Gets the current VIP level.\n    pub fn vip_level(&self) -> OKXVipLevel {\n        let level = self.vip_level.load(Ordering::Relaxed);\n        OKXVipLevel::from(level)\n    }\n\n    /// Connect to the OKX WebSocket server.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the connection process fails.\n    pub async fn connect(&mut self) -> anyhow::Result<()> {\n        let connect_lock = Arc::clone(&self.connect_lock);\n        let _connect_guard = connect_lock.lock().await;\n\n        if !self.handler_tasks.is_empty() && !self.handler_tasks.all_finished() {\n            anyhow::bail!(\"Cannot connect while previous WebSocket handler task is still running\");\n        }\n\n        if !self.handler_tasks.is_open() || !self.handler_tasks.is_empty() {\n            self.handler_tasks.begin_shutdown();\n            self.handler_tasks\n                .finish_shutdown(Duration::from_secs(2), Duration::from_secs(2))\n                .await\n                .map_err(|e| anyhow::anyhow!(\"Previous WebSocket handler failed: {e}\"))?;\n            self.handler_tasks.start_generation().map_err(|e| {\n                anyhow::anyhow!(\"Failed to start WebSocket handler task generation: {e}\")\n            })?;\n        }\n        let handler_spawner = self.handler_tasks.spawner().map_err(|e| {\n            anyhow::anyhow!(\"Failed to acquire WebSocket handler task spawner: {e}\")\n        })?;\n        let handler_abort = CancellationToken::new();\n        *self.handler_abort.lock() = handler_abort.clone();\n        let mut rollback = ConnectRollback {","sourceCodeStart":582,"sourceCodeEnd":618,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/okx/src/websocket/client.rs#L582-L618","documentation":"`connect` enforces that no previous WebSocket handler task is still alive before starting a new connection. If a prior handler task exists and has not finished (still connected/subscribed), starting another would double-handle messages, so the call fails with this error.","triggerScenarios":"Calling `connect()` on an already-connected client, or reconnecting while a prior connection's handler tasks are still running (no prior `disconnect()`).","commonSituations":"Reconnect logic that calls `connect` again after a transient drop without awaiting `disconnect` first; test code or retry loops re-invoking `connect` on a live client.","solutions":["Call `disconnect()` (and await it) before calling `connect()` again.","Reuse the existing connected client instead of reconnecting.","Ensure `all_finished()` becomes true by letting prior tasks shut down (the client will auto-shutdown stale tasks only when not open); check `is_active` before connecting."],"exampleFix":"// before\nif !client.is_active() { client.connect().await?; } // stale handler may still run\n// after\nclient.disconnect().await?;\nclient.connect().await?;","handlingStrategy":"try-catch","validationCode":"// only connect when no handler tasks are pending\nif client.is_active() || !client.is_disconnected() {\n    // skip connect or disconnect first\n}","typeGuard":null,"tryCatchPattern":"match client.connect().await {\n    Ok(()) => {},\n    Err(e) if e.to_string().contains(\"previous WebSocket handler task\") => {\n        client.disconnect().await?;\n        client.connect().await?;\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always await disconnect() before reconnecting.","Track connection state in your supervisor and call connect only from a disconnected state.","Use a single owner task for the client lifecycle to avoid concurrent connect calls."],"tags":["okx","websocket","lifecycle","state"],"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"}