BigPizzaV3/CodexPlusPlus · error · anyhow::Error

No injectable page target found

Error message

No injectable page target found

What it means

pick_page_target selects a Chrome tab to inject into from a /json target list. A target is injectable only when target_type equals page and web_socket_debugger_url is present and non-empty; the picker then prefers the primary Codex page and otherwise falls back to the first injectable page. This error means not a single target in the list was injectable: there were no page-type targets, or every page lacked a WebSocket debugger URL.

Source

Thrown at crates/codex-plus-core/src/cdp.rs:252

}

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());
    }

    bail!("No injectable page target found")
}

pub fn pick_injectable_codex_page_target(targets: &[CdpTarget]) -> anyhow::Result<CdpTarget> {
    let priorities: [fn(&CdpTarget) -> bool; 4] = [
        is_exact_codex_app_main_target,
        is_primary_codex_app_target,
        is_chatgpt_desktop_page_target,
        is_supported_codex_page_target,
    ];
    for matches_priority in priorities {
        if let Some(target) = targets
            .iter()
            .find(|target| is_injectable_page_target(target) && matches_priority(target))
        {
            return Ok(target.clone());
        }
    }
    bail!("No injectable Codex page target found")

View on GitHub (pinned to f2074595a2)

Solutions

  1. Open or keep at least one regular tab in the browser being debugged
  2. Relaunch the browser with --remote-debugging-port=PORT (not --remote-debugging-pipe) so pages expose webSocketDebuggerUrl
  3. Verify the list came from http://127.0.0.1:PORT/json and includes targets of type page
  4. Close other DevTools clients holding sessions on the pages, then re-query

Example fix

// before: selection on a possibly empty list
let target = pick_page_target(&targets)?;
// after: ensure an injectable page exists first
ensure_browser_has_open_page(&client, debug_port).await?;
let targets = query_targets_url(&client, &list_url, debug_port).await?;
let target = pick_page_target(&targets)?;
Defensive patterns

Strategy: validation

Validate before calling

let injectable = targets.iter().any(|t| t.target_type == "page" && t.web_socket_debugger_url.as_deref().is_some_and(|u| !u.is_empty()));
if !injectable {
    // open a tab or relaunch with --remote-debugging-port, then re-query
}

Type guard

fn has_injectable_page_target(targets: &[CdpTarget]) -> bool {
    targets.iter().any(|t| t.target_type == "page" && t.web_socket_debugger_url.as_deref().is_some_and(|u| !u.is_empty()))
}

Try / catch

if let Err(e) = pick_page_target(&targets) {
    if e.to_string().contains("No injectable page target") {
        open_or_relaunch_browser().await?;
        let targets = requery_targets(debug_port).await?;
        return pick_page_target(&targets);
    }
    return Err(e);
}

Prevention

When it happens

Trigger: Passing a CdpTarget list where all targets are service_worker, background_page, iframe or other non-page types; querying /json when every tab is closed; the browser was launched with --remote-debugging-pipe instead of a port so pages expose no webSocketDebuggerUrl.

Common situations: Headless Chrome started with pipe-based debugging; all tabs closed by selection time; target list fetched from /json/version or a non-Chromium endpoint that returns no targets array; DevTools already holding the only debug session on the page.

Related errors


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