Hmbown/CodeWhale · error
Failed to write review payload
Error message
Failed to write review payload: {e} What it means
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.
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`
Example fix
// before
let child = Command::new("gh").arg("api")...spawn()?;
// after
let status = Command::new("gh").arg("auth").arg("status").status()?;
if !status.success() { bail!("gh is not authenticated; run gh auth login"); }
let child = Command::new("gh").arg("api")...spawn()?; Defensive patterns
Strategy: try-catch
Validate before calling
// Rust
if std::process::Command::new("gh").arg("auth").arg("status").status().map(|s| s.success()) != Ok(true) {
bail!("gh CLI is missing or unauthenticated; run gh auth login");
} Try / catch
// Rust
match post_review(&payload) {
Ok(()) => info!("review posted"),
Err(e) if e.to_string().contains("Failed to write review payload") => {
warn!("gh exited before reading stdin: {e:#}; check gh auth and retry");
*publication = ReviewPublication::Uncertain;
}
Err(e) => return Err(e),
} Prevention
- 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
When it happens
Trigger: `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.
Common situations: `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.
Related errors
- Failed to wait for `gh api
- Failed to write to
- Failed to write to
- stdin is not available for task
- API key input is unexpectedly large
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/91c270579f0766c8.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/lib.rs:9734
.ok_or_else(|| anyhow::anyhow!("gh not found on PATH"))?;
cmd.arg("api")
.arg("--method")
.arg("POST")
.arg(format!("repos/{repo}/pulls/{number}/reviews"))
.arg("--input")
.arg("-")
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped());
let mut child = cmd
.spawn()
.map_err(|e| anyhow::anyhow!("Failed to run `gh api`: {e}"))?;
*publication = ReviewPublication::Uncertain;
if let Some(stdin) = child.stdin.as_mut() {
use std::io::Write;
stdin
.write_all(serde_json::to_string(&payload)?.as_bytes())
.map_err(|e| anyhow::anyhow!("Failed to write review payload: {e}"))?;
}
let output = child
.wait_with_output()
.map_err(|e| anyhow::anyhow!("Failed to wait for `gh api`: {e}"))?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
bail!("gh api POST repos/{repo}/pulls/{number}/reviews failed: {stderr}");
}
*publication = ReviewPublication::Posted;
Ok(())
}
/// Publish a completed PR review exactly once: resolve the repository, render
/// the summary, and include every comment whose position the diff confirms.
/// A failed request can have an uncertain remote outcome, so reconciliation
/// and any retry stay under the caller's control rather than risking a duplicate.
fn post_pr_review(
number: u32,View on GitHub (pinned to 73e0f67d83)