{"record":{"id":"d699bf5fbee079f3","repo":"Kuberwastaken/claurst","slug":"cdp-error","errorCode":null,"errorMessage":"CDP error: {}","messagePattern":"CDP error: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-rust/crates/commands/src/chrome.rs","lineNumber":82,"sourceCode":"\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\n\r\n    // -----------------------------------------------------------------------\r\n    // Session take/restore helpers\r\n    //\r\n    // We avoid holding a MutexGuard across await points by taking ownership\r\n    // of the session, performing all async operations with it, then putting\r\n    // it back into the global.\r\n    // -----------------------------------------------------------------------\r\n\r\n    fn take_session() -> anyhow::Result<ChromeSession> {\r\n        SESSION.lock().take().ok_or_else(|| {\r\n            anyhow::anyhow!(\"No active Chrome session. Run `/chrome connect` first.\")\r","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/Kuberwastaken/claurst/blob/b0637c97ec34144387cbf2f74f65df6d16a6cef1/src-rust/crates/commands/src/chrome.rs#L64-L100","documentation":"Chrome replied to a CDP command with a JSON-RPC-style error object instead of a result. cdp_call detects val[\"error\"] for the matching request id and surfaces the entire error value (method, message, data) via this anyhow message. The library itself is fine; Chrome rejected the command.","triggerScenarios":"In cdp_call, the response with the matching id contains an \"error\" key: e.g. CDP commands issued to the wrong target type, invalid parameters, \"No node with given id\" from stale DOM references, or Page.navigate to an unreachable URL.","commonSituations":"Calling Page/DOM commands on a target that doesn't support them (e.g. service worker or browser target); acting on a DOM node removed by a prior navigation; invalid selector or node id; protocol version mismatch between the client and Chrome.","solutions":["Read the embedded CDP error detail in the message; it names the failing method and reason.","Re-query the DOM/target after navigation instead of reusing stale node ids or selectors.","Connect to a page target rather than the browser/service-worker target for page commands.","Check Chrome version compatibility for the CDP method being used."],"exampleFix":"// before\nlet val: Value = serde_json::from_str(&text)?;\nif val[\"id\"] == id {\n    if let Some(err) = val.get(\"error\") {\n        return Err(anyhow::anyhow!(\"CDP error: {}\", err));\n    }\n    return Ok(val);\n}\n// after\n// re-acquire fresh node references after any navigation before retrying DOM commands\nlet document = cdp_call(ws, \"DOM.getDocument\", json!({})).await?;\nlet node = cdp_call(ws, \"DOM.querySelector\", json!({\"nodeId\": document[\"result\"][\"root\"][\"nodeId\"], \"selector\": sel})).await?;","handlingStrategy":"try-catch","validationCode":"// use a browser target (type=page) for page-level CDP commands\nlet targets: Vec<Value> = reqwest::get(\"http://localhost:9222/json\").await?.json().await?;\nassert!(targets.iter().any(|t| t[\"type\"] == \"page\"));","typeGuard":"fn is_cdp_error(val: &serde_json::Value) -> bool {\n    val.get(\"error\").is_some()\n}","tryCatchPattern":"// match on the CDP error code for targeted recovery\nif let Some(err) = val.get(\"error\") {\n    if err[\"message\"].as_str().unwrap_or(\"\").contains(\"No node with given id\") {\n        return Err(anyhow!(\"stale node id: re-run DOM.getDocument\"));\n    }\n    return Err(anyhow!(\"CDP error: {}\", err));\n}","preventionTips":["Re-query DOM.getDocument / DOM.querySelector after every navigation","Connect to 'page' targets, not browser or service-worker targets, for page commands","Keep Chrome updated so the CDP surface matches the methods you call"],"tags":["chrome","cdp","devtools","api-error"],"backgroundTag":"api-error-response","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"}