{"record":{"id":"eec84992d0decf4b","repo":"Hmbown/CodeWhale","slug":"gh-api-post-repos-repo-pulls-number-reviews-failed-stderr","errorCode":null,"errorMessage":"gh api POST repos/{repo}/pulls/{number}/reviews failed: {stderr}","messagePattern":"gh api POST repos/(.+?)/pulls/(.+?)/reviews failed: (.+?)","errorType":"error_code","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/lib.rs","lineNumber":9741,"sourceCode":"        .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,\n    view: &GhPullRequest,\n    repo: Option<&str>,\n    review: &crate::tools::review::ReviewOutput,\n    diff: &str,\n    publication: &mut ReviewPublication,\n) -> Result<()> {\n    crate::tools::review_pr::ensure_current(number, repo, &std::env::current_dir()?, view)?;","sourceCodeStart":9723,"sourceCodeEnd":9759,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/lib.rs#L9723-L9759","documentation":"The code shells out to `gh api POST repos/{repo}/pulls/{number}/reviews` to publish a PR review. When the gh subprocess exits non-zero, its stderr is surfaced verbatim in this error. It means GitHub rejected the review-creation request.","triggerScenarios":"`gh api` call to create a PR review fails: expired/missing gh auth token, wrong PR number, repo renamed or inaccessible, network failure, or review body rejected by GitHub (e.g. invalid markdown payload size).","commonSituations":"gh session expired (`gh auth token` stale after SSO logout); publishing to a private repo the token cannot read; a fork where the PR number belongs to the upstream repo; corporate proxy blocking api.github.com.","solutions":["Run `gh auth status` and re-authenticate with `gh auth login` / `gh auth refresh -s repo`","Verify the PR exists and is reachable: `gh api repos/{repo}/pulls/{number}` with the same repo/number values","Re-read the stderr embedded in the error — it contains GitHub's specific reason (401/403/404/422) and address that directly"],"exampleFix":"// before\n$ gh auth status  # token expired\n// after\n$ gh auth login && gh auth status  # logged in, retry publish","handlingStrategy":"try-catch","validationCode":"if std::process::Command::new(\"gh\").arg(\"auth\").arg(\"status\").status().map(|s|!s.success()).unwrap_or(true) { /* prompt re-auth before publishing */ }","typeGuard":null,"tryCatchPattern":"match publish_result { Err(e) if e.to_string().contains(\"gh api POST\") => { // inspect embedded stderr; check gh auth status, PR number, repo access before retry } , Ok(_) => {} }","preventionTips":["Run `gh auth status` in CI before publishing reviews","Confirm the PR number belongs to the target repo (forks: use upstream)","Verify token scopes include repo/review permissions after SSO changes"],"tags":["cli","github","api","http-error"],"backgroundTag":"api-error-response","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"}