BigPizzaV3/CodexPlusPlus · error · anyhow::Error
CDP WebSocket port {port} does not match debug port {expecte
Error message
CDP WebSocket port {port} does not match debug port {expected_port} What it means
CodexPlusPlus hardens CDP target discovery: every webSocketDebuggerUrl returned by the browser must use ws/wss, point at a loopback IP, carry an explicit port, and that port must equal the debug port used to fetch the target list (validate_cdp_websocket_url in crates/codex-plus-core/src/cdp.rs). This error means the WebSocket URL embedded in a CDP target carries a different port than the port you queried, so the library refuses the connection as a possible SSRF/redirect to another debugger endpoint.
Source
Thrown at crates/codex-plus-core/src/cdp.rs:231
if !matches!(parsed.scheme(), "ws" | "wss") {
bail!("CDP WebSocket URL must use ws or wss");
}
let host = parsed
.host_str()
.ok_or_else(|| anyhow::anyhow!("CDP WebSocket URL has no host"))?;
let address = host
.trim_start_matches('[')
.trim_end_matches(']')
.parse::<IpAddr>()
.with_context(|| "CDP WebSocket host must be a loopback IP address")?;
if !address.is_loopback() {
bail!("CDP WebSocket host must be loopback");
}
let port = parsed
.port()
.ok_or_else(|| anyhow::anyhow!("CDP WebSocket URL must include an explicit port"))?;
if port != expected_port {
bail!("CDP WebSocket port {port} does not match debug port {expected_port}");
}
Ok(())
}
pub fn pick_page_target(targets: &[CdpTarget]) -> anyhow::Result<CdpTarget> {
let mut first_page = None;
for target in targets
.iter()
.filter(|target| is_injectable_page_target(target))
{
first_page.get_or_insert(target);
if is_primary_codex_page_target(target) {
return Ok(target.clone());
}
}
if let Some(target) = first_page {
return Ok(target.clone());View on GitHub (pinned to f2074595a2)
Solutions
- Re-query the /json target list from the exact same port you pass as debug_port so both sides agree
- Launch the browser with a fixed port, e.g. --remote-debugging-port=9222, and use 9222 everywhere
- In port-mapped setups (Docker, SSH forwards) run validation from inside the same network namespace, or validate against the port the ws URL actually uses
- Discard cached CdpTarget lists whenever the browser process restarts
Example fix
// before: list fetched from one port, validated against another
let targets = query_targets_url(&client, &list_url, old_debug_port).await?;
// after: derive list URL and expected port from one value
let debug_port = 9222;
let list_url = format!("http://127.0.0.1:{debug_port}/json");
let targets = query_targets_url(&client, &list_url, debug_port).await?; Defensive patterns
Strategy: validation
Validate before calling
let parsed = reqwest::Url::parse(websocket_url)?;
if parsed.port() != Some(debug_port) {
// re-query /json from this exact port before connecting
targets = query_targets_url(&client, &list_url_on(debug_port), debug_port).await?;
} Try / catch
match validate_cdp_websocket_url(url, debug_port) {
Ok(()) => {}
Err(e) if e.to_string().contains("does not match debug port") => { targets = requery_targets(debug_port).await?; }
Err(e) => return Err(e),
} Prevention
- Derive the list URL and the expected port from one variable
- Launch the browser with a fixed --remote-debugging-port
- Drop cached target lists when the browser process restarts
When it happens
Trigger: Calling query_targets_url(client, http-URL-on-port-P, P) or validate_cdp_websocket_url(url, expected_port) directly where target.web_socket_debugger_url carries another port: the browser was relaunched and picked a new ephemeral --remote-debugging-port, a cached target list from an older browser instance is reused, or a port-mapped setup (container 9222 published as host 9223) makes the ws URL port differ from the host-side port.
Common situations: Chrome/Chromium restarted without a fixed debug port; Docker port-publish remapping the devtools port; a proxy rewriting host or port; tests mixing a targets list fetched from port A with validation against port B.
Related errors
- No injectable page target found
- Page.captureScreenshot returned invalid PNG data
- periodic Runtime.evaluate reported unavailable capability
- No injectable Codex page target found
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@f2074595a2 (2026-08-23).
Data as JSON: /api/errors/b9e5d6f9f1f0bda4.
Report an issue: GitHub.