{"record":{"id":"20bae905790f086b","repo":"Kuberwastaken/claurst","slug":"websocket-closed-unexpectedly","errorCode":null,"errorMessage":"WebSocket closed unexpectedly","messagePattern":"WebSocket closed unexpectedly","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-rust/crates/commands/src/chrome.rs","lineNumber":70,"sourceCode":"    // -----------------------------------------------------------------------\r\n\r\n    /// Send a CDP method call and wait for the matching response.\r\n    /// Returns the full response object (including `result` / `error`).\r\n    async fn cdp_call(\r\n        ws: &mut WebSocketStream<MaybeTlsStream<TcpStream>>,\r\n        method: &str,\r\n        params: Value,\r\n    ) -> anyhow::Result<Value> {\r\n        let id = next_id();\r\n        let request = json!({ \"id\": id, \"method\": method, \"params\": params });\r\n        ws.send(WsMessage::Text(request.to_string())).await?;\r\n\r\n        // Drain messages until we get the one with our id (ignore events).\r\n        loop {\r\n            let raw = ws\r\n                .next()\r\n                .await\r\n                .ok_or_else(|| anyhow::anyhow!(\"WebSocket closed unexpectedly\"))??;\r\n            let text: String = match raw {\r\n                WsMessage::Text(t) => t.to_string(),\r\n                WsMessage::Ping(_) | WsMessage::Pong(_) => continue,\r\n                WsMessage::Close(_) => {\r\n                    return Err(anyhow::anyhow!(\"WebSocket closed by Chrome\"));\r\n                }\r\n                _ => continue,\r\n            };\r\n            let val: Value = serde_json::from_str(&text)?;\r\n            if val[\"id\"] == id {\r\n                if let Some(err) = val.get(\"error\") {\r\n                    return Err(anyhow::anyhow!(\"CDP error: {}\", err));\r\n                }\r\n                return Ok(val);\r\n            }\r\n            // It's an event or different response — keep waiting.\r\n        }\r\n    }\r","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/Kuberwastaken/claurst/blob/b0637c97ec34144387cbf2f74f65df6d16a6cef1/src-rust/crates/commands/src/chrome.rs#L52-L88","documentation":"In cdp_call, the WebSocket stream returned None from ws.next(), i.e. the stream ended without a Close frame being surfaced as a message. The code maps that to this error while draining messages to find the response with the matching request id. It means the DevTools WebSocket connection was torn down before Chrome answered the CDP command.","triggerScenarios":"During the drain loop in cdp_call, StreamExt::next() yields None: the underlying tungstenite socket was closed by the peer at the transport level, or the connection task ended, before a Text message with the request id arrived.","commonSituations":"Chrome/Chromium crashed or was killed mid-session; the page/tab navigated or closed, destroying the target; DevTools port (e.g. 9222) proxy dropped the connection; network interruption to the debug endpoint.","solutions":["Reconnect via the connect command/function to re-establish the WebSocket and retry the operation.","Verify Chrome is still running and the remote debugging port is alive (curl http://localhost:9222/json/version).","Re-launch Chrome with --remote-debugging-port and retry the navigation/screenshot command.","Check whether the target tab was closed; operate on a stable tab instead of one that navigates away."],"exampleFix":"// before\nlet raw = ws.next().await.ok_or_else(|| anyhow::anyhow!(\"WebSocket closed unexpectedly\"))??;\n// after\nmatch ws.next().await {\n    Some(Ok(msg)) => { /* continue processing */ }\n    Some(Err(e)) => return Err(anyhow::anyhow!(\"WebSocket error: {}\", e)),\n    None => return Err(anyhow::anyhow!(\"WebSocket closed unexpectedly\")),\n}","handlingStrategy":"retry","validationCode":"// check the debug endpoint is alive before sending CDP commands\nreqwest::get(\"http://localhost:9222/json/version\").await?;","typeGuard":null,"tryCatchPattern":"// reconnect once and retry the CDP call\nmatch cdp_call(&mut ws, method, params).await {\n    Err(e) if e.to_string().contains(\"closed\") => {\n        ws = connect(ws_url).await?;\n        cdp_call(&mut ws, method, params).await\n    }\n    other => other,\n}","preventionTips":["Verify Chrome is running with --remote-debugging-port before automating","Ping /json/version between long operations to detect dead sessions","Avoid operating on tabs that will close or navigate away mid-command"],"tags":["websocket","chrome","cdp","connection"],"backgroundTag":"websocket-closed-unexpectedly","analyzedSha":"b0637c97ec34144387cbf2f74f65df6d16a6cef1","analyzedAt":"2026-09-10T00:24:58.650Z","contentChangedAt":"2026-09-10T00:24:58.650Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}