Hmbown/CodeWhale · error

Failed to wait for `gh api

Error message

Failed to wait for `gh api`: {e}

What it means

Raised when the code fails to reap the spawned `gh api` child process via `wait_with_output()` while posting a PR review. This is an OS-level I/O failure around the child process (spawn/pipe/read), not a GitHub HTTP error — HTTP-level failures are surfaced separately via the stderr bail right after. The review post is aborted with an uncertain publication state.

Solutions

  1. Retry the review-post operation; this is usually a transient OS-level failure
  2. Check system resource limits (ulimit -n for fd exhaustion) and raise if processes/fds are leaking
  3. Ensure no other code path in the app reaps the same child (would cause wait to fail)
  4. If persistent, capture `gh api` output via a temp file instead of pipes to sidestep pipe-read failures

Example fix

// before
let output = child.wait_with_output()
    .map_err(|e| anyhow::anyhow!("Failed to wait for `gh api`: {e}"))?;
// after
let output = match child.wait_with_output() {
    Ok(o) => o,
    Err(e) => { tracing::warn!("gh api wait failed: {e}; retrying once"); child2.wait_with_output()? }
};
Defensive patterns

Strategy: try-catch

Try / catch

// Rust
let output = child.wait_with_output()
    .map_err(|e| anyhow::anyhow!("Failed to wait for `gh api`: {e}"))
    .with_context(|| format!("waiting for gh api on {repo}#{number}"))?;
if !output.status.success() {
    let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
    bail!("gh api failed: {stderr}");
}

Prevention

When it happens

Trigger: `child.wait_with_output()` returns Err while waiting for the `gh api POST repos/{repo}/pulls/{number}/reviews` process — e.g. the process was reaped elsewhere first, the runtime could not read its stdout/stderr pipes, or the process was killed in a way that makes wait fail.

Common situations: Process reapers/monitors that double-reap children; resource exhaustion (fork failures, fd limits) under load; container runtimes with unusual process semantics; intermittent OS-level I/O errors.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/8fb34e15ce1e4f59. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/lib.rs:9738

        .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: &GhPullRequest,
    repo: Option<&str>,
    review: &crate::tools::review::ReviewOutput,
    diff: &str,

View on GitHub (pinned to 73e0f67d83)