Hmbown/CodeWhale · error
gh pr view did not return exact base and head commit IDs
Error message
gh pr view did not return exact base and head commit IDs
What it means
view_with shells out to `gh pr view --json <fields>` and deserializes the JSON into GhPullRequest. After parsing it validates that base_sha and head_sha are exact 40-char commit IDs via commit_id(); if either is missing, abbreviated, or otherwise not an exact SHA, the review tool refuses the PR because all later diff/receipt logic pins to exact base/head commits.
Solutions
- Run `gh pr view <number> --json baseRefOid,headRefOid` manually and confirm both fields contain full 40-character SHAs
- Upgrade or repair the gh CLI to a version that returns exact oids (`gh --version`); remove any wrapper script shadowing gh in PATH
- Re-push the PR branch so headRefOid resolves, and ensure the base branch still exists on the remote
Example fix
// before: trusting whatever gh returned
let view: GhPullRequest = serde_json::from_str(&run(Program::Gh, &args)?)?;
// after: fail fast with a clear message when oids are missing
let view: GhPullRequest = serde_json::from_str(&run(Program::Gh, &args)?)
.context("gh pr view returned incomplete PR metadata")?;
if !commit_id(&view.base_sha) || !commit_id(&view.head_sha) {
bail!("gh pr view did not return exact base and head commit IDs");
} Defensive patterns
Strategy: validation
Validate before calling
// check gh output before handing to the review tool
let out = std::process::Command::new("gh").args(["pr","view",&num,"--json","baseRefOid,headRefOid"]).output()?;
let v: serde_json::Value = serde_json::from_slice(&out.stdout)?;
let is_full_sha = |s: &str| s.len() == 40 && s.chars().all(|c| c.is_ascii_hexdigit());
assert!(is_full_sha(v["baseRefOid"].as_str().unwrap_or("")) && is_full_sha(v["headRefOid"].as_str().unwrap_or("")), "gh did not return full commit SHAs"); Type guard
fn commit_id(s: &str) -> bool { s.len() == 40 && s.chars().all(|c| c.is_ascii_hexdigit()) } Try / catch
match view_with(number, repo) {
Err(e) if e.to_string().contains("exact base and head commit IDs") => eprintln!("gh returned incomplete metadata; upgrade gh and retry"),
other => other?,
} Prevention
- Pin a recent gh CLI version and verify `gh --version` in setup scripts
- Pre-flight `gh pr view <n> --json baseRefOid,headRefOid` and assert full 40-char SHAs
- Avoid wrapper scripts that reformat gh's JSON output
When it happens
Trigger: `gh pr view` returns JSON whose baseRefOid or headRefOid is empty, abbreviated, or not a full 40-hex commit; the deserialize succeeds but the commit_id() check fails.
Common situations: Older or nonstandard gh CLI versions that omit/shorten oid fields; GitHub Enterprise with proxies that rewrite responses; a PR whose base branch was deleted so the base oid resolves oddly; corporate wrappers around gh emitting different JSON shapes.
Related errors
- baseline provenance must identify a clean source tree
- baseline provenance needs an exact source SHA
- expected revision must be an exact 40-character Git SHA
- GitHub tag ref did not include an object SHA
- persistence measurement source tree is dirty
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/5e07516d952d79c1.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/tools/review_pr.rs:90
return false;
};
commit_id(old) && commit_id(new) && old.len() == new.len()
}
fn view_with(
number: u32,
repo: Option<&str>,
run: &mut impl FnMut(Program, &[String]) -> Result<String>,
) -> Result<GhPullRequest> {
if number == 0 {
bail!("A positive pull request number is required");
}
let mut args = pr_args("view", number, repo);
args.extend(["--json".into(), VIEW_FIELDS.into()]);
let view: GhPullRequest = serde_json::from_str(&run(Program::Gh, &args)?)
.context("gh pr view returned incomplete PR metadata")?;
if !commit_id(&view.base_sha) || !commit_id(&view.head_sha) {
bail!("gh pr view did not return exact base and head commit IDs");
}
Ok(view)
}
pub(crate) fn fetch_view(
number: u32,
repo: Option<&str>,
workspace: &Path,
) -> Result<GhPullRequest> {
view_with(number, repo, &mut |program, args| {
run_command(workspace, program, args)
})
}
fn same_revision(expected: &GhPullRequest, current: &GhPullRequest) -> Result<()> {
if expected.head_sha != current.head_sha
|| expected.base_sha != current.base_sha
|| expected.changed_files != current.changed_filesView on GitHub (pinned to 73e0f67d83)