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

  1. Re-query the /json target list from the exact same port you pass as debug_port so both sides agree
  2. Launch the browser with a fixed port, e.g. --remote-debugging-port=9222, and use 9222 everywhere
  3. 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
  4. 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

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


AI-assisted analysis of BigPizzaV3/CodexPlusPlus@f2074595a2 (2026-08-23). Data as JSON: /api/errors/b9e5d6f9f1f0bda4. Report an issue: GitHub.