{"record":{"id":"826bdd1a9a2d611f","repo":"nautechsystems/nautilus_trader","slug":"failed-to-acquire-websocket-handler-task-spawner-826bdd","errorCode":null,"errorMessage":"Failed to acquire WebSocket handler task spawner: {e}","messagePattern":"Failed to acquire WebSocket handler task spawner: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/okx/src/websocket/client.rs","lineNumber":614,"sourceCode":"        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 {\n            handler_tasks: Arc::clone(&self.handler_tasks),\n            signal: Arc::clone(&self.signal),\n            handler_abort: handler_abort.clone(),\n            socket_control: self.socket_control.clone(),\n            armed: true,\n        };\n\n        // Reset signal so is_active()/is_closed() work after a previous close()\n        self.signal.store(false, Ordering::Release);\n\n        let (message_handler, raw_rx) = channel_message_handler();\n\n        // No-op ping handler: handler owns the WebSocketClient and responds to pings directly\n        // in the message loop for minimal latency (see handler.rs TEXT_PONG response)","sourceCodeStart":596,"sourceCodeEnd":632,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/okx/src/websocket/client.rs#L596-L632","documentation":"In OKX WebSocket `connect`, after starting a new handler generation, the client acquires a spawner used to launch per-stream handler tasks. If `spawner()` fails (task group not in a spawnable state), connect fails with this error before opening the connection.","triggerScenarios":"connect called when `handler_tasks.spawner()` returns Err — the task group was not successfully started (e.g. generation start failed silently, group is closed/shutting down, or acquired concurrently by another connect).","commonSituations":"Reconnect storms sharing a single client instance; calling connect on a client whose close() has already begun; race between connect and disconnect on different tasks.","solutions":["Ensure the client is not closed/shutting down before calling connect.","Avoid concurrent connect calls on the same client; use a single supervisor task that owns the connection lifecycle.","Retry connect with backoff; the transient task-group state usually resolves after the prior generation finishes."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// rust\nif let Err(e) = client.connect().await {\n    if e.to_string().contains(\"handler task spawner\") {\n        tokio::time::sleep(Duration::from_secs(1)).await;\n        client.connect().await?;\n    } else { return Err(e); }\n}","preventionTips":["Keep a single owner task for the connection lifecycle.","Check the client is not closed before connecting.","Back off between reconnect attempts."],"tags":["websocket","okx","concurrency","task-group"],"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"}