{"record":{"id":"91c270579f0766c8","repo":"Hmbown/CodeWhale","slug":"failed-to-write-review-payload-e","errorCode":null,"errorMessage":"Failed to write review payload: {e}","messagePattern":"Failed to write review payload: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/lib.rs","lineNumber":9734,"sourceCode":"        .ok_or_else(|| anyhow::anyhow!(\"gh not found on PATH\"))?;\n    cmd.arg(\"api\")\n        .arg(\"--method\")\n        .arg(\"POST\")\n        .arg(format!(\"repos/{repo}/pulls/{number}/reviews\"))\n        .arg(\"--input\")\n        .arg(\"-\")\n        .stdin(std::process::Stdio::piped())\n        .stdout(std::process::Stdio::piped())\n        .stderr(std::process::Stdio::piped());\n    let mut child = cmd\n        .spawn()\n        .map_err(|e| anyhow::anyhow!(\"Failed to run `gh api`: {e}\"))?;\n    *publication = ReviewPublication::Uncertain;\n    if let Some(stdin) = child.stdin.as_mut() {\n        use std::io::Write;\n        stdin\n            .write_all(serde_json::to_string(&payload)?.as_bytes())\n            .map_err(|e| anyhow::anyhow!(\"Failed to write review payload: {e}\"))?;\n    }\n    let output = child\n        .wait_with_output()\n        .map_err(|e| anyhow::anyhow!(\"Failed to wait for `gh api`: {e}\"))?;\n    if !output.status.success() {\n        let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();\n        bail!(\"gh api POST repos/{repo}/pulls/{number}/reviews failed: {stderr}\");\n    }\n    *publication = ReviewPublication::Posted;\n    Ok(())\n}\n\n/// Publish a completed PR review exactly once: resolve the repository, render\n/// the summary, and include every comment whose position the diff confirms.\n/// A failed request can have an uncertain remote outcome, so reconciliation\n/// and any retry stay under the caller's control rather than risking a duplicate.\nfn post_pr_review(\n    number: u32,","sourceCodeStart":9716,"sourceCodeEnd":9752,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/lib.rs#L9716-L9752","documentation":"This error is raised while posting a PR review via the GitHub CLI: the code spawns `gh api` and writes the JSON review payload to its stdin. If `stdin.write_all` fails (the child process has exited or its pipe is broken), it wraps the io::Error into this anyhow error. It means the review request never reached `gh`, so nothing was posted.","triggerScenarios":"`stdin.write_all(serde_json::to_string(&payload)?.as_bytes())` fails while posting a review through `gh api POST repos/{repo}/pulls/{number}/reviews` — typically because the `gh` process exited before consuming stdin (e.g. bad auth made it exit immediately) or the pipe broke.","commonSituations":"`gh` not authenticated or removed/upgraded mid-call so it exits early and closes stdin; a wrapper/shim on PATH for `gh` that doesn't read stdin; JSON payload large enough to fill the pipe buffer after early child exit (broken pipe / EPIPE); sandboxed environments that kill spawned processes.","solutions":["Run `gh auth status` and re-authenticate with `gh auth login` so the spawned `gh api` process doesn't exit before reading stdin","Verify `which gh` points to the real GitHub CLI, not a wrapper that ignores stdin","Retry the post; transient EPIPE on a freshly spawned child often resolves on a second attempt","Upgrade gh (`gh upgrade` or package manager) — older versions had stdin-handling issues with `gh api`"],"exampleFix":"// before\nlet child = Command::new(\"gh\").arg(\"api\")...spawn()?;\n// after\nlet status = Command::new(\"gh\").arg(\"auth\").arg(\"status\").status()?;\nif !status.success() { bail!(\"gh is not authenticated; run gh auth login\"); }\nlet child = Command::new(\"gh\").arg(\"api\")...spawn()?;","handlingStrategy":"try-catch","validationCode":"// Rust\nif std::process::Command::new(\"gh\").arg(\"auth\").arg(\"status\").status().map(|s| s.success()) != Ok(true) {\n    bail!(\"gh CLI is missing or unauthenticated; run gh auth login\");\n}","typeGuard":null,"tryCatchPattern":"// Rust\nmatch post_review(&payload) {\n    Ok(()) => info!(\"review posted\"),\n    Err(e) if e.to_string().contains(\"Failed to write review payload\") => {\n        warn!(\"gh exited before reading stdin: {e:#}; check gh auth and retry\");\n        *publication = ReviewPublication::Uncertain;\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Verify `gh auth status` passes in the deployment environment before review automation runs","Pin/upgrade gh to a current version known to read stdin on `gh api`","Avoid wrapping gh in shell scripts that don't forward stdin","Treat publication as Uncertain until Posted, as the code already does"],"tags":["process","stdin","github-cli","broken-pipe"],"backgroundTag":"broken-pipe","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}