{"record":{"id":"3b0ef79564b789ce","repo":"BigPizzaV3/CodexPlusPlus","slug":"cdp-websocket-closed-before-response-for-method-id-message","errorCode":null,"errorMessage":"CDP websocket closed before response for {method} id {message_id}","messagePattern":"CDP websocket closed before response for (.+?) id (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/bridge.rs","lineNumber":716,"sourceCode":"                    \"method\": method,\n                    \"params\": params,\n                })\n                .to_string()\n                .into(),\n            ))\n            .await\n            .with_context(|| format!(\"failed to send CDP command {method} id {message_id}\"))?;\n        Ok(())\n    }\n\n    async fn wait_for_id(&mut self, message_id: u64, method: String) -> anyhow::Result<Value> {\n        loop {\n            if let Some(response) = self.responses.remove(&message_id) {\n                return command_result(response, &method, message_id);\n            }\n\n            let Some(message) = self.next_message().await? else {\n                bail!(\"CDP websocket closed before response for {method} id {message_id}\");\n            };\n\n            if let Some(response_id) = message.get(\"id\").and_then(Value::as_u64) {\n                if response_id == message_id {\n                    return command_result(message, &method, message_id);\n                }\n                self.responses.insert(response_id, message);\n            }\n        }\n    }\n\n    async fn next_message(&mut self) -> anyhow::Result<Option<Value>> {\n        let Some(message) = self.socket.next().await else {\n            return Ok(None);\n        };\n        let message = message.context(\"failed to read CDP websocket message\")?;\n        let Message::Text(text) = message else {\n            return Ok(Some(json!({})));","sourceCodeStart":698,"sourceCodeEnd":734,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/crates/codex-plus-core/src/bridge.rs#L698-L734","documentation":"wait_for_id pumps incoming CDP messages until a response whose id matches the pending command arrives. If next_message() returns None — the websocket stream ended — any still-pending command can never be answered, so the session bails with \"CDP websocket closed before response for {method} id {message_id}\". It reports the method and message id of the abandoned command.","triggerScenarios":"The browser/tab closed, the debug port dropped the connection, or the page navigated in a way that tore down the CDP session while send_command was awaiting its response.","commonSituations":"Target tab was closed or crashed during a long-running command; DevTools remote debugging port dropped; the app under automation exited; network interruption to the CDP endpoint; awaiting a command the target never answers and the socket then closes.","solutions":["Reconnect to the CDP websocket (connect_cdp_websocket) and re-issue the command in a fresh session","Check the target is still alive (correct websocket_url, tab not closed/crashed) before sending","Wrap CDP session usage in retry-once logic that re-establishes the connection on this error","For long operations, keep the target page open and avoid navigation that invalidates the session"],"exampleFix":"// before\nlet resp = session.send_command(id, method, params).await?;\n// after\nlet resp = match session.send_command(id, method, params).await {\n    Ok(r) => r,\n    Err(e) if e.to_string().contains(\"websocket closed\") => {\n        session = reconnect(websocket_url).await?;\n        session.send_command(id, method, params).await?\n    }\n};","handlingStrategy":"retry","validationCode":"// confirm the CDP endpoint is alive before sending\nlet ws_ok = tokio_tungstenite::connect_async(&websocket_url).await.is_ok();\nif !ws_ok { eprintln!(\"CDP endpoint unreachable\"); }","typeGuard":null,"tryCatchPattern":"match session.send_command(id, method, params).await {\n    Ok(r) => r,\n    Err(e) if e.to_string().contains(\"websocket closed before response\") => {\n        session = CdpSession::new(connect_cdp_websocket(&websocket_url).await?);\n        session.send_command(id, method, params).await?\n    }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Keep the target tab/app open for the duration of automation","Reconnect and retry once on closed-socket errors before surfacing failure","Monitor the target process/tab lifecycle; long commands are the most exposed to drops"],"tags":["cdp","websocket","connection-closed","devtools"],"backgroundTag":"connection-refused","analyzedSha":"b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6","analyzedAt":"2026-09-19T23:35:21.129Z","contentChangedAt":"2026-09-19T23:35:21.129Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}