{"record":{"id":"bbbe9397f832533f","repo":"nautechsystems/nautilus_trader","slug":"polymarket-websocket-handler-failed-error","errorCode":null,"errorMessage":"Polymarket WebSocket handler failed: {error}","messagePattern":"Polymarket WebSocket handler failed: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/polymarket/src/websocket/client.rs","lineNumber":456,"sourceCode":"\n    /// Disconnects the WebSocket connection.\n    pub async fn disconnect(&mut self) -> anyhow::Result<()> {\n        log::debug!(\"Disconnecting Polymarket WebSocket\");\n        self.signal.store(true, Ordering::Relaxed);\n\n        if let Err(e) = self.cmd_tx.read().await.send(HandlerCommand::Disconnect) {\n            log::debug!(\"Failed to send disconnect (handler may already be shut down): {e}\");\n        }\n\n        let task_result = match finish_task(\n            &mut self.task_handle,\n            std::time::Duration::from_secs(2),\n            std::time::Duration::from_secs(2),\n        )\n        .await\n        {\n            None | Some(TaskJoinOutcome::Completed(()) | TaskJoinOutcome::Aborted) => Ok(()),\n            Some(TaskJoinOutcome::Failed(error)) => Err(anyhow::anyhow!(\n                \"Polymarket WebSocket handler failed: {error}\"\n            )),\n            Some(TaskJoinOutcome::Incomplete) => Err(anyhow::anyhow!(\n                \"Polymarket WebSocket handler did not stop after abort\"\n            )),\n        };\n        // Invalidate after the task has stopped so any in-flight auth_tracker.succeed()\n        // calls from the handler cannot race with and survive the invalidation.\n        self.auth_tracker.invalidate();\n\n        if let Some(control) = &self.socket_control {\n            control.deregister();\n        }\n        log::debug!(\"Polymarket WebSocket disconnected\");\n        task_result\n    }\n\n    /// Returns `true` if the WebSocket is actively connected.","sourceCodeStart":438,"sourceCodeEnd":474,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/polymarket/src/websocket/client.rs#L438-L474","documentation":"disconnect() aborts the feed-handler task and joins it with a 2s timeout. TaskJoinOutcome::Failed means the handler task finished on its own but returned an Err; disconnect() surfaces that handler error as 'Polymarket WebSocket handler failed: {error}'. The {error} text is the handler's own failure cause (connection, auth, parse, etc.), so the real diagnosis lives in the wrapped message.","triggerScenarios":"Calling disconnect() while (or after) the handler task has terminated with an error — e.g. the WebSocket stream errored out, an auth call failed, or message parsing returned a fatal error that ended the handler's run loop.","commonSituations":"Shutdown racing a handler that just died from a network drop; credentials revoked mid-session so the handler exits with an auth error; a malformed venue message causing a fatal parse error in the handler loop.","solutions":["Read the wrapped {error} in the message — it names the handler's actual failure; fix that root cause","Treat it as non-fatal during shutdown if you only wanted the task gone: the session is stopped either way","If auth-related, refresh API credentials before reconnecting","Add retries/backoff on reconnect if the handler repeatedly dies from transient network errors"],"exampleFix":"// before\nclient.disconnect().await?; // propagates handler's own failure\n// after\nif let Err(e) = client.disconnect().await {\n    log::warn!(\"disconnect reported handler failure (session stopped anyway): {e:#}\");\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match client.disconnect().await {\n    Ok(()) => {},\n    Err(e) if e.to_string().starts_with(\"Polymarket WebSocket handler failed\") => {\n        // handler already dead with its own error; session is stopped either way\n        log::warn!(\"handler failed during disconnect: {e:#}\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always inspect the wrapped inner error — it names the handler's real failure","Give WebSocket reads/writes in the handler explicit timeouts so errors surface predictably","Refresh credentials before reconnecting when the wrapped error is auth-related","Log handler exits at warn/error level so disconnect-time failures are not surprising"],"tags":["rust","websocket","task","polymarket"],"backgroundTag":"background-task-failed","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"}