BigPizzaV3/CodexPlusPlus · error

Codex injection failed

Error message

Codex injection failed

What it means

The launcher retries injecting the Codex helper script into the Codex browser page over CDP in a loop; each failed attempt records the error in last_error and sleeps 500ms. When the loop exits without a successful injection, it returns the last recorded error — or this generic message via unwrap_or_else when last_error is None, i.e. the loop body never recorded any error at all. It is a fallback sentinel indicating injection never got off the ground rather than a specific failure.

Solutions

  1. Verify the browser is running with the CDP debug port enabled and that the port matches the launcher configuration
  2. Check launcher logs immediately before this error for earlier concrete per-attempt errors (those are the real cause)
  3. Increase the retry window/retries if the Codex page loads slowly
  4. Ensure the loop always assigns last_error on failure so future errors carry a concrete cause instead of this sentinel

Example fix

// before
Err(last_error.unwrap_or_else(|| anyhow::anyhow!("Codex injection failed")))
// after
Err(last_error.unwrap_or_else(|| {
    anyhow::anyhow!("Codex injection failed: no attempt completed within the retry window (check CDP debug port and browser state)")
}))
Defensive patterns

Strategy: retry

Validate before calling

// 检查 CDP 调试端口可达后再触发注入
let targets = reqwest::get(format!("http://127.0.0.1:{debug_port}/json")).await?;
if !targets.status().is_success() {
    anyhow::bail!("CDP debug port {debug_port} not responding; browser not started with remote debugging?");
}

Try / catch

match launcher.inject_codex().await {
    Ok(()) => {},
    Err(e) if e.to_string().contains("Codex injection failed") => {
        eprintln!("injection never started; check CDP port and browser state: {e}");
        // 手动重启带调试端口的浏览器后重试
    }
    Err(e) => eprintln!("injection attempt error: {e}"),
}

Prevention

When it happens

Trigger: The injection retry loop in the launcher finished all attempts without success and last_error was None — meaning no injection attempt ever executed or stored an error (e.g. the loop never entered its attempt branch), so unwrap_or_else produced this placeholder message instead of a concrete cause.

Common situations: Browser not launched with the expected CDP debug port, injected page never became available within the retry window, browser closed mid-retry, or a refactor left the loop unable to reach the injection call so last_error stays None.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19). Data as JSON: /api/errors/a40cbaf2da9d3d01. Report an issue: GitHub.

Appendix: source

Thrown at apps/codex-plus-launcher/src/main.rs:1026

async fn inject_with_context(
    debug_port: u16,
    helper_port: u16,
    ctx: BridgeContext,
    runtime: Arc<LauncherRuntimeService>,
) -> anyhow::Result<()> {
    let mut last_error = None;
    for _ in 0..20 {
        match try_inject_with_context(debug_port, helper_port, ctx.clone(), runtime.clone()).await {
            Ok(()) => return Ok(()),
            Err(error) => {
                last_error = Some(error);
                tokio::time::sleep(std::time::Duration::from_millis(500)).await;
            }
        }
    }

    Err(last_error.unwrap_or_else(|| anyhow::anyhow!("Codex injection failed")))
}

fn remote_control_recovery_is_superseded_by_openai(
    settings: &codex_plus_core::settings::BackendSettings,
    request: &codex_plus_core::remote_control_recovery::PendingRemoteControlRecovery,
) -> bool {
    settings.active_relay_id == request.profile_id
        && settings.active_relay_session_provider()
            == codex_plus_core::settings::RelaySessionProvider::Openai
}

async fn try_inject_with_context(
    debug_port: u16,
    helper_port: u16,
    ctx: BridgeContext,
    runtime: Arc<LauncherRuntimeService>,
) -> anyhow::Result<()> {
    let targets = codex_plus_core::cdp::list_targets(debug_port).await?;

View on GitHub (pinned to b1ed92e5e4)