{"record":{"id":"be96d087e3be6451","repo":"nikivdev/code","slug":"failed-to-read-from-codex-app-server","errorCode":null,"errorMessage":"failed to read from codex app-server: {}","messagePattern":"failed to read from codex app-server: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/skills.rs","lineNumber":1122,"sourceCode":"    let mut line = serde_json::to_string(msg)?;\n    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    }","sourceCodeStart":1104,"sourceCodeEnd":1140,"githubUrl":"https://github.com/nikivdev/code/blob/a747e741ae92c09071d0ae946ab48488adcff1ce/src/skills.rs#L1104-L1140","documentation":"codex_read_response reads the codex app-server's stdout line by line via std::io::Lines. When the underlying BufReader hits an I/O error, the Some(Err(err)) arm surfaces it wrapped in this message. It means the pipe to the child process failed at the OS/read level, not that the child exited.","triggerScenarios":"The ChildStdout reader returns an io::Error during lines.next() while reload_codex_skills_for_cwd awaits a response — e.g. the pipe broke, a descriptor error occurred, or the OS returned EIO.","commonSituations":"Child process killed abruptly mid-response; fd limits or resource exhaustion breaking the pipe; running in a container/sandbox that severs the pipe; disk or memory pressure causing read failures.","solutions":["Check whether the codex app-server process was killed (OOM killer, signal) around the time of the error","Retry the operation; transient pipe errors often resolve on restart","Verify system resource limits (ulimit -n) and memory headroom","Inspect stderr of the child for why the pipe failed"],"exampleFix":"// before\nbail!(\"failed to read from codex app-server: {}\", err)\n// after: classify the error for better diagnosis\nbail!(\"failed to read from codex app-server (kind={:?}): {}\", err.kind(), err)","handlingStrategy":"retry","validationCode":"// ensure the child process is alive before reading\nif let Ok(Some(status)) = child.try_wait() {\n    eprintln!(\"codex app-server already exited: {}\", 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(\"failed to read from codex app-server\") => {\n        log::warn!(\"io error talking to app-server: {e:#}; restarting\");\n        restart_and_retry()?;\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Monitor for OOM killer / signal kills of the child process","Keep file descriptor limits healthy (ulimit -n)","Avoid running in sandboxes that sever parent-child pipes","Restart the app-server on transient read failures with capped retries"],"tags":["io","ipc","codex","process"],"backgroundTag":"broken-pipe","analyzedSha":"a747e741ae92c09071d0ae946ab48488adcff1ce","analyzedAt":"2026-09-01T22:43:55.719Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}