{"record":{"id":"0484181cb4f11286","repo":"nikivdev/code","slug":"codex-app-server-closed-stdout-unexpectedly-048418","errorCode":null,"errorMessage":"codex app-server closed stdout unexpectedly","messagePattern":"codex app-server closed stdout unexpectedly","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/skills.rs","lineNumber":1123,"sourceCode":"    line.push('\\n');\n    writer.write_all(line.as_bytes())?;\n    writer.flush()?;\n    Ok(())\n}\n\nfn codex_read_response(\n    lines: &mut std::io::Lines<std::io::BufReader<std::process::ChildStdout>>,\n    expected_id: u64,\n    deadline: Instant,\n) -> Result<serde_json::Value> {\n    loop {\n        if Instant::now() >= deadline {\n            bail!(\"codex app-server response timed out\");\n        }\n        let line = match lines.next() {\n            Some(Ok(line)) => line,\n            Some(Err(err)) => bail!(\"failed to read from codex app-server: {}\", err),\n            None => bail!(\"codex app-server closed stdout unexpectedly\"),\n        };\n        if line.trim().is_empty() {\n            continue;\n        }\n        let msg: serde_json::Value = serde_json::from_str(&line)\n            .with_context(|| format!(\"invalid JSON from codex app-server: {}\", line))?;\n        if msg.get(\"id\").and_then(|v| v.as_u64()) == Some(expected_id) {\n            if let Some(err) = msg.get(\"error\") {\n                let message = err\n                    .get(\"message\")\n                    .and_then(|v| v.as_str())\n                    .unwrap_or(\"unknown codex app-server error\");\n                bail!(\"codex app-server error: {}\", message);\n            }\n            return Ok(msg);\n        }\n    }\n}","sourceCodeStart":1105,"sourceCodeEnd":1141,"githubUrl":"https://github.com/nikivdev/code/blob/a747e741ae92c09071d0ae946ab48488adcff1ce/src/skills.rs#L1105-L1141","documentation":"codex_read_response expects the codex app-server to keep its stdout open until it answers. When lines.next() returns None, the stream reached EOF — the child closed stdout (typically because the process exited or crashed) without sending the expected response. The error is thrown so callers see a clear cause instead of an empty reply.","triggerScenarios":"The codex app-server child exits or its stdout closes before it emits the JSON response matching expected_id during reload_codex_skills_for_cwd; the process crashes on startup; the process is killed by a signal.","commonSituations":"Codex binary panics on the request; wrong codex executable path causing an immediate exit; version mismatch where the server exits on unknown requests; OOM kill of the child process.","solutions":["Run the codex app-server manually and reproduce the request to see its exit output/stderr","Check the child's exit status after failure to capture why it exited (crash, panic, signal)","Verify the codex binary version/protocol compatibility","Ensure the child is spawned with inherited/stderr captured so crash reasons are visible"],"exampleFix":"// before\nNone => bail!(\"codex app-server closed stdout unexpectedly\"),\n// after: include exit status captured elsewhere\nNone => bail!(\"codex app-server closed stdout unexpectedly (exit status: {:?})\", child.try_wait()),","handlingStrategy":"try-catch","validationCode":"// verify the child is still alive before expecting a response\nif let Ok(Some(status)) = child.try_wait() {\n    bail!(\"codex app-server already exited with {} before responding\", status);\n}","typeGuard":null,"tryCatchPattern":"match codex_read_response(&mut lines, expected_id, deadline) {\n    Ok(msg) => handle(msg),\n    Err(e) if e.to_string().contains(\"closed stdout unexpectedly\") => {\n        eprintln!(\"codex app-server crashed; stderr was: {stderr}\");\n        restart_app_server()?;\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always capture the app-server's stderr so crash reasons are visible","Pin a codex binary version compatible with your request protocol","Check child exit status immediately after any stream EOF","Handle known crash triggers (bad cwd, missing workspace) before sending requests"],"tags":["ipc","codex","process","stdout"],"backgroundTag":"process-exited-unexpectedly","analyzedSha":"a747e741ae92c09071d0ae946ab48488adcff1ce","analyzedAt":"2026-09-01T22:43:55.719Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}