{"record":{"id":"393b4a64bba37cac","repo":"openai/codex","slug":"standalone-codex-updater-request-failed-with-statu","errorCode":null,"errorMessage":"standalone Codex updater request failed with status {status}","messagePattern":"standalone Codex updater request failed with status (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"codex-rs/app-server-daemon/src/update_loop.rs","lineNumber":205,"sourceCode":"    drop(stdin);\n    let status = child\n        .wait()\n        .await\n        .context(\"failed to wait for standalone Codex updater\")?;\n\n    if status.success() {\n        Ok(())\n    } else {\n        anyhow::bail!(\"standalone Codex updater exited with status {status}\")\n    }\n}\n\n#[cfg(unix)]\nasync fn fetch_installer_script(http: &impl InstallerHttp) -> Result<Vec<u8>> {\n    match http.get(INSTALL_URL).await? {\n        InstallerResponse::Success(body) => Ok(body),\n        InstallerResponse::Unsuccessful { status } => {\n            anyhow::bail!(\"standalone Codex updater request failed with status {status}\")\n        }\n    }\n}\n\n#[cfg(unix)]\n#[derive(Clone, Debug, PartialEq, Eq)]\nenum InstallerResponse {\n    Success(Vec<u8>),\n    Unsuccessful { status: u16 },\n}\n\n#[cfg(unix)]\n/// HTTP boundary used to download the standalone installer.\n///\n/// Implementations must issue a GET for the supplied URL, return exact response bytes for a\n/// successful status, and report a non-success status without buffering its response body.\ntrait InstallerHttp: Send + Sync {\n    fn get<'a>(","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/openai/codex/blob/339751715c64496cb86246bfb3935f40e309dd3d/codex-rs/app-server-daemon/src/update_loop.rs#L187-L223","documentation":"fetch_installer_script issues a GET against the hardcoded INSTALL_URL https://chatgpt.com/codex/install.sh through the route-aware HTTP pool. Transport failures surface as separate errors; this one means the request completed and the server answered a non-success HTTP status, which the client reports as InstallerResponse::Unsuccessful and converts into this bail. The loop then retries on the next hourly cycle.","triggerScenarios":"An update tick where chatgpt.com answers 4xx or 5xx for the install script: 403 or 451 from an intercepting proxy or regional block, 404 if the endpoint was retired, 429 rate limiting, or 5xx during a CDN incident; also the unit test installer_fetch_rejects_non_success_status feeding Unsuccessful deliberately.","commonSituations":"Locked-down corporate networks with TLS-inspecting proxies; CI environments with egress allowlists that omit chatgpt.com; transient CDN outages; stale builds after the install endpoint moves.","solutions":["Check the status directly: curl -I https://chatgpt.com/codex/install.sh and map the code (403/451 proxy or region, 404 outdated build, 429/5xx transient).","Allow chatgpt.com and the script's download hosts through the proxy or egress rules.","On 404, update to a current codex build; the endpoint moved.","On 429 or 5xx, wait: the hourly loop retries automatically and there is nothing to fix locally."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Pre-flight the endpoint before enabling the update loop in\n// restricted environments:\nlet resp = reqwest::get(\"https://chatgpt.com/codex/install.sh\").await?;\nif !resp.status().is_success() {\n    return Err(anyhow!(\"egress blocks the installer: HTTP {}\", resp.status()));\n}","typeGuard":null,"tryCatchPattern":"match fetch_result {\n    Ok(script) => { /* proceed */ }\n    Err(err) if err.to_string().contains(\"request failed with status\") => {\n        // HTTP-level failure: retry with backoff on 5xx/429, fail fast with\n        // a proxy or URL hint on 4xx.\n        tracing::warn!(error = err.to_string(), \"install script fetch failed; retrying next cycle\");\n    }\n    Err(err) => return Err(err),\n}","preventionTips":["Allowlist chatgpt.com and the installer's download hosts in proxy and egress configurations.","Watch for 4xx statuses persisting across cycles: they indicate configuration drift or a moved endpoint, not transient failure.","Note that run() swallows per-cycle errors and retries hourly; add logging when you need per-cycle visibility."],"tags":["http","installer","status-code","network","updater"],"backgroundTag":"http-error-status","analyzedSha":"339751715c64496cb86246bfb3935f40e309dd3d","analyzedAt":"2026-08-25T05:35:09.876Z","schemaVersion":2},"datasetVersion":"2026-08-25T06:17:31.827Z"}