{"record":{"id":"8d0d4d5b509bc459","repo":"BigPizzaV3/CodexPlusPlus","slug":"cdp-websocket-url-must-include-an-explicit-port","errorCode":null,"errorMessage":"CDP WebSocket URL must include an explicit port","messagePattern":"CDP WebSocket URL must include an explicit port","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/bridge.rs","lineNumber":291,"sourceCode":"}\n\npub fn reject_bridge_expression(request_id: &str, message: &str) -> anyhow::Result<String> {\n    Ok(format!(\n        \"window.__codexSessionDeleteReject({}, {})\",\n        serde_json::to_string(request_id)?,\n        serde_json::to_string(message)?,\n    ))\n}\n\nasync fn connect_cdp_websocket(\n    websocket_url: &str,\n) -> anyhow::Result<\n    tokio_tungstenite::WebSocketStream<tokio_tungstenite::MaybeTlsStream<tokio::net::TcpStream>>,\n> {\n    let parsed = reqwest::Url::parse(websocket_url).context(\"invalid CDP WebSocket URL\")?;\n    let port = parsed\n        .port()\n        .ok_or_else(|| anyhow::anyhow!(\"CDP WebSocket URL must include an explicit port\"))?;\n    crate::cdp::validate_cdp_websocket_url(websocket_url, port)?;\n    let (socket, _) = tokio::time::timeout(CDP_CONNECT_TIMEOUT, connect_async(websocket_url))\n        .await\n        .with_context(|| {\n            format!(\n                \"timed out connecting CDP websocket after {}s\",\n                CDP_CONNECT_TIMEOUT.as_secs()\n            )\n        })?\n        .context(\"failed to connect CDP websocket\")?;\n\n    Ok(socket)\n}\n\nstruct CdpSession<S> {\n    socket: S,\n    responses: HashMap<u64, Value>,\n    binding_calls: VecDeque<Value>,","sourceCodeStart":273,"sourceCodeEnd":309,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/1f431ae49b57b3055e0e6845ba6156c6b4232b4d/crates/codex-plus-core/src/bridge.rs#L273-L309","documentation":"connect_cdp_websocket (crates/codex-plus-core/src/bridge.rs:291) parses the ws URL and requires Url::port() to be Some before validating it against the debug port. For ws/wss schemes reqwest::Url has no well-known default port (only http/https/ftp do), so a URL like ws://127.0.0.1/devtools/browser/<id> without ':9222' yields port()==None and this error fires. It is a strict-input guard: the code refuses to guess a port.","triggerScenarios":"Passing a CDP WebSocket URL assembled by hand or trimmed of its port, e.g. ws://localhost/devtools/browser/abc, into any bridge helper that connects (screenshot, command send); URLs taken from the browser's /json/version endpoint always carry the explicit port and never trigger this.","commonSituations":"User config stores a sanitized URL without the port; code copies webSocketDebuggerUrl but strips ':9222' via a rewriting rule; a different default debug port (not 9222) makes hand-written URLs omit it; proxy/URL normalization middleware drops 'unnecessary' ports.","solutions":["Include the explicit port in the URL: ws://127.0.0.1:9222/devtools/browser/<id>","Source the URL from the browser itself: GET http://127.0.0.1:<port>/json/version and use its webSocketDebuggerUrl verbatim (it always includes the port)","If accepting user input, parse with Url and reject/repair port-less ws URLs before they reach the connector"],"exampleFix":"# before: no port — Url::port() returns None for ws scheme\nws://127.0.0.1/devtools/browser/4f8a... \n\n# after: explicit port matching the remote debugging port\nws://127.0.0.1:9222/devtools/browser/4f8a...","handlingStrategy":"validation","validationCode":"// Validate shape before connecting\nlet u = reqwest::Url::parse(ws_url).context(\"invalid CDP WebSocket URL\")?;\nlet port = u.port().context(\"CDP WebSocket URL must include an explicit port\")?;\nvalidate_cdp_websocket_url(ws_url, port)?; // also enforces ws/wss + loopback + port match","typeGuard":"fn cdp_url_has_explicit_port(url: &str) -> bool {\n    reqwest::Url::parse(url).ok().and_then(|u| u.port()).is_some()\n}","tryCatchPattern":"match connect_cdp_websocket(ws_url).await {\n    Ok(socket) => Ok(socket),\n    Err(e) if e.to_string().contains(\"explicit port\") => {\n        // repair by re-fetching the canonical URL from the browser\n        let fresh = fetch_websocket_debugger_url(port).await?;\n        connect_cdp_websocket(&fresh).await\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Always source ws URLs from /json/version's webSocketDebuggerUrl — it carries the port","Never hand-assemble or sanitize CDP URLs by stripping components","Validate scheme+host+port before any connect attempt"],"tags":["cdp","websocket","url-parsing","port"],"backgroundTag":"websocket-url-missing-port","analyzedSha":"1f431ae49b57b3055e0e6845ba6156c6b4232b4d","analyzedAt":"2026-08-16T20:54:18.598Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}