Codex PR reviews can cite unresolvable commit SHAs for commit-metadata findings
What issue are you seeing?
Codex PR review reports git metadata from a commit that is not the one under review
Component: Codex code review on GitHub pull requests (thechatgpt-codex-connector bot), not the codex CLI.
Summary
When Codex reviews a pull request and makes a claim about commit
metadata — author, committer, or trailers — the claim describes a
commit object that does not exist in the repository. The SHA it cites
cannot be resolved by git cat-file, and the GitHub API returns422 No commit found for SHA.
The object it is describing appears to be a locally reconstructed copy
of the pull request, authored by Codex <codex@openai.com>, rather than
the commit the review is pinned to. The review's ownReviewed commit: <sha> line names the correct commit, so the right SHA
is available to it at the time it writes the wrong one.
Why this matters
The unresolvable SHA is the visible half. The invisible half is worse:
- When Codex pastes the SHA, you get a citation that obviously fails,
and you can catch it.
- When it does not paste a SHA, you get the same false claim with
nothing to check it against — "this commit records both author and
committer as Codex <codex@openai.com>" about a commit that records
neither.
So every Codex finding about authorship, committer identity, or trailer
presence should currently be treated as unverified. In our case these
were P1-badged findings instructing us to rewrite published history to
fix a violation that did not exist.
The trigger appears to be a repository whose AGENTS.md states an
attribution invariant, e.g.:
- Author and committer stay the owner's identity:
`owner <12345678+owner@users.noreply.github.com>`.
- Every commit carries a `Co-Authored-By` trailer naming the specific
agent that did the work.
Codex correctly goes looking for compliance. It then inspects the wrong
object and reports non-compliance.
Worked example — three findings, all false, all on one commit
A review was pinned to a commit we will call C. Ground truth for C,
from a fully-fetched clone:
$ git show -s --format='author=%an <%ae>%ncommitter=%cn <%ce>' C
author=owner <12345678+owner@users.noreply.github.com>
committer=owner <12345678+owner@users.noreply.github.com>
$ git show -s --format='%(trailers)' C
Source: original
Co-Authored-By: GitHub CodeQL <noreply@github.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SrsmdXL5SfzAMahUjYBirP
Codex posted three P1 findings against C in one run. Quoted verbatim,
with only the owner's identity substituted:
Restore the owner's author and committer identity Recreate this commit withowner <12345678+owner@users.noreply.github.com>as both author and committer. Fresh evidence for this rerun isgit cat-file -p b9ad53b8cc1526dd0b02e4b3a1f56678bc7e026b, which identifiesCodex <codex@openai.com>in both fields; the earlier review's reference to814b6614was incorrect, but the specified commit itself still violates the mandatory ownership invariant.
Add the implementing agent's co-author trailer Fresh evidence for this rerun is git show -s --format='%(trailers)' b9ad53b8cc1526dd0b02e4b3a1f56678bc7e026b, which returns no co-author trailer.
Record the content source as a Git trailer Fresh evidence for this rerun isgit show -s --format='%(trailers)' b9ad53b8cc1526dd0b02e4b3a1f56678bc7e026b, which parses only the trailing session URL and noSource:entry.
All three are false of C, which has the owner as author and committer,
a Source: trailer, and two Co-Authored-By: trailers. All three would
be true of a freshly created commit whose message was not C's message.
Neither cited SHA exists:
$ git cat-file -t b9ad53b8cc1526dd0b02e4b3a1f56678bc7e026b
fatal: Not a valid object name b9ad53b8cc1526dd0b02e4b3a1f56678bc7e026b
$ git cat-file -t 814b6614
fatal: Not a valid object name 814b6614
The fingerprint: a different SHA on every run of the same commit
The two reviews quoted above ran nine minutes apart and were pinned
to the same commit C:
| review | pinned to | SHA cited as evidence |
|:--|:--|:--|
| 19:03:20Z | C | 814b6614 |
| 19:12:08Z | C | b9ad53b8cc1526dd0b02e4b3a1f56678bc7e026b |
The second review states *"the earlier review's reference to 814b6614
was incorrect" and calls its own SHA "fresh evidence for this rerun"* —
which is consistent with a new object being constructed per run, and not
with a hallucinated string or a garbage-collected GitHub object.
The same pattern appears on another pull request: same head commit,
reviews 3 hours apart, two different unresolvable SHAs
(66ec3458d18d1a51eba25026df3f5a3bcd1fe009, then33d44f264701f3080bd39813fbc1945def70c0aa).
Ruling out the obvious alternatives
- Not a hallucinated string. The SHAs are stable within a run and
used consistently across multiple findings in that run.
- Not a force-push or rebase losing the object. The reviews are
pinned to commits that still exist; in one case the two runs share the
identical pin.
- Not GitHub's
refs/pull/N/mergepreview. We fetched both
refs/pull/N/head and refs/pull/N/merge for the affected pull
request; the cited SHA is neither.
- Not an abbreviation collision. Several of the unresolvable
citations are full 40-character SHAs.
- Consistent with a squash/replay onto the base. On one pull request
Codex reported that the cited object had a single parent and that the
reviewed commit was not an ancestor of it. The commit the review was
actually pinned to is a two-parent merge (git rev-list --parents -n 1
returns 3 tokens). A rebuilt single-parent commit on top of the base
explains that reading exactly.
Survey across one repository
Every figure below was produced by re-running the sweep at the time of
writing, over a private repository, using the GitHub REST API for all
three surfaces Codex writes on (inline review comments, conversation
comments, review bodies). SHAs appearing inside /blob/ URLs are
excluded, because those are correct — they use the real GitHub SHA.
| check | result |
|:--|:--|
| pull requests on the repository | 54 |
| Codex comments swept (inline + conversation + review bodies) | 172 |
| pull requests carrying Codex output | 24 |
| SHA-shaped citations outside blob URLs | 58 |
| distinct SHAs cited | 51 |
| distinct SHAs that resolve to no commit | 9 |
| of those, how many exist in the local clone | 0 |
| of those, how many GitHub's API can find | 0 |
| commits those same reviews were PINNED to, that do resolve | 8 |
| of those pinned commits, how many are authored by Codex | 0 |
Affected reviews span 2026-08-21 to 2026-08-26. The unresolvable
SHAs occur only in git-command evidence (git show, git cat-file,git rev-list), never in blob URLs and never in the Reviewed commit:
pin — which is the clearest signal that two different sources of truth
are in play within a single review.
Minimal reproduction
This does not require our repository. It reproduces from scratch on any
new public repo.
1. Create a repo whose contract makes Codex inspect commit metadata.
git init codex-repro && cd codex-repro
git config user.name "Repro Owner"
git config user.email "owner@example.com"
cat > AGENTS.md <<'EOF'
# Contract
- Author and committer stay the owner's identity:
`Repro Owner <owner@example.com>`.
- Every commit carries a `Co-Authored-By` trailer naming the specific
agent that did the work.
- Every commit carries a `Source:` trailer.
EOF
echo hello > file.txt
git add -A
git commit -m "$(printf 'chore: initial commit\n\nSource: original\nCo-Authored-By: Some Agent <noreply@example.com>\n')"
git branch -M main
# create an EMPTY public repo on GitHub first, then:
git remote add origin https://github.com/<you>/codex-repro.git
git push -u origin main
2. Make a branch with one commit that satisfies the contract.
git checkout -b change
echo world >> file.txt
git add -A
git commit -m "$(printf 'feat: add a line\n\nSource: original\nCo-Authored-By: Some Agent <noreply@example.com>\n')"
git push -u origin change
gh pr create --fill --base main --head change
3. Record ground truth before the review runs.
git show -s --format=fuller HEAD
git show -s --format='%(trailers)' HEAD
git rev-parse HEAD
Both author and committer are Repro Owner <owner@example.com>, and both
trailers are present.
4. Trigger the review, asking specifically for commit metadata so the
claim is forced rather than incidental:
gh pr comment <N> --body "@codex review — verify this branch against AGENTS.md, and state the head commit's author, committer and trailers with the git command you used."
5. Compare. In the resulting inline comments:
# the SHA Codex cites in its git-command evidence
git cat-file -t <sha-codex-cited> # expect: fatal: Not a valid object name
gh api repos/<you>/codex-repro/commits/<sha-codex-cited> # expect: 422
# the SHA the review says it reviewed
grep 'Reviewed commit' <review body> # this one resolves fine
Expected
Findings about author, committer and trailers are computed from the
commit named in Reviewed commit:, and any SHA quoted as evidence
resolves in the repository under review.
Actual
Findings are computed from a different commit object, authored byCodex <codex@openai.com>, which exists only inside the review
environment. Any SHA quoted from it resolves nowhere, and the resulting
findings are false whenever the real commit satisfies the contract.
Suggested direction
Two things would independently remove the class:
- Compute git-metadata findings from the reviewed commit, i.e. the
one already named in Reviewed commit: — or from
refs/pull/N/head — rather than from a locally reconstructed object.
- **Never quote a SHA that is not resolvable in the repository under
review.** If the review environment must work on a rebuilt object,
the evidence rendered to the user should be translated back to the
upstream SHA, or the finding should be suppressed. A citation that
cannot be checked is worse than no citation, because it reads as
verifiable.
Notes
- All quoted comment text is verbatim from the bot, with only the
repository owner's name and email substituted.
- The repository surveyed is private, so the pull request links are not
included; the reproduction above is self-contained and does not depend
on it.
What steps can reproduce the bug?
Minimal reproduction
This does not require our repository. It reproduces from scratch on any
new public repo.
1. Create a repo whose contract makes Codex inspect commit metadata.
git init codex-repro && cd codex-repro
git config user.name "Repro Owner"
git config user.email "owner@example.com"
cat > AGENTS.md <<'EOF'
# Contract
- Author and committer stay the owner's identity:
`Repro Owner <owner@example.com>`.
- Every commit carries a `Co-Authored-By` trailer naming the specific
agent that did the work.
- Every commit carries a `Source:` trailer.
EOF
echo hello > file.txt
git add -A
git commit -m "$(printf 'chore: initial commit\n\nSource: original\nCo-Authored-By: Some Agent <noreply@example.com>\n')"
git branch -M main
# create an EMPTY public repo on GitHub first, then:
git remote add origin https://github.com/<you>/codex-repro.git
git push -u origin main
2. Make a branch with one commit that satisfies the contract.
git checkout -b change
echo world >> file.txt
git add -A
git commit -m "$(printf 'feat: add a line\n\nSource: original\nCo-Authored-By: Some Agent <noreply@example.com>\n')"
git push -u origin change
gh pr create --fill --base main --head change
3. Record ground truth before the review runs.
git show -s --format=fuller HEAD
git show -s --format='%(trailers)' HEAD
git rev-parse HEAD
Both author and committer are Repro Owner <owner@example.com>, and both
trailers are present.
4. Trigger the review, asking specifically for commit metadata so the
claim is forced rather than incidental:
gh pr comment <N> --body "@codex review — verify this branch against AGENTS.md, and state the head commit's author, committer and trailers with the git command you used."
5. Compare. In the resulting inline comments:
# the SHA Codex cites in its git-command evidence
git cat-file -t <sha-codex-cited> # expect: fatal: Not a valid object name
gh api repos/<you>/codex-repro/commits/<sha-codex-cited> # expect: 422
# the SHA the review says it reviewed
grep 'Reviewed commit' <review body> # this one resolves fine
What is the expected behavior?
Expected
Findings about author, committer and trailers are computed from the
commit named in Reviewed commit:, and any SHA quoted as evidence
resolves in the repository under review.
Actual
Findings are computed from a different commit object, authored byCodex <codex@openai.com>, which exists only inside the review
environment. Any SHA quoted from it resolves nowhere, and the resulting
findings are false whenever the real commit satisfies the contract.
Additional information
Suggested direction
Two things would independently remove the class:
- Compute git-metadata findings from the reviewed commit, i.e. the
one already named in Reviewed commit: — or from
refs/pull/N/head — rather than from a locally reconstructed object.
- **Never quote a SHA that is not resolvable in the repository under
review.** If the review environment must work on a rebuilt object,
the evidence rendered to the user should be translated back to the
upstream SHA, or the finding should be suppressed. A citation that
cannot be checked is worse than no citation, because it reads as
verifiable.
Notes
- All quoted comment text is verbatim from the bot, with only the
repository owner's name and email substituted.
- The repository surveyed is private, so the pull request links are not
included; the reproduction above is self-contained and does not depend
on it.