A review on #701 was lost to a GitHub 422, and the logs cannot say why.
What happened
| time |
event |
| 20:53:03 |
ready_for_review → review starts on sha ee78bfe |
| 20:53:20 |
synchronize → head moves to d4389d2 (a merge of main). ReviewDispatcher logs Coalescing review for devops-thiago/ThrillhouseBot #701 — 1 superseded request(s), latest sha: d4389d2, and the in-flight run keeps going |
| 21:02:37 |
model responds after ~9.5 minutes — 100,860 tokens, 65,339 of them reasoning |
| 21:02:39 |
POST /pulls/701/reviews → 422, ReviewPostException, user sees "review could not be completed" |
| 21:02:40 |
the coalesced run for d4389d2 starts from scratch |
ERROR [ReviewOrchestrator] Review failed for devops-thiago/ThrillhouseBot #701:
ReviewPostException: GitHub review rejected for devops-thiago/ThrillhouseBot #701
Caused by: ClientWebApplicationException: Received: 'Unprocessable Entity, status code 422'
when invoking REST Client method: 'GitHubReviewClient#createReviewOnce'
Established from the logs and the API: the request carried no inline comments
(createReviewWithFallback throws ReviewPostException only when req.comments().isEmpty(), and no
"retrying without comments" warning was logged), the round had 0 new findings and 0 unresolved
previous, so this was postNoIssuesReview. Not a force-push — ee78bfe is still a commit of the PR.
Not a draft — converted to draft 19:05, back to ready 20:53:02. Not an over-long body —
CreateReviewRequest caps it through CommentBodyLimit.
1. The 422 body is never logged
DefaultMicroprofileRestClientExceptionMapper surfaces the status and nothing else, so GitHub's
message — the one thing that would name the cause — is discarded. The failure is undiagnosable after
the fact, which is why this issue can rank causes but not state one.
Two candidates remain: a commit_id (ee78bfe) that is 9.5 minutes and one merge commit stale, or
something specific to the APPROVE event. Worth noting for the second: every bot review on this
repository is COMMENTED; none has ever landed as APPROVED, so this plausibly was the first
APPROVE attempt.
Fix: capture the response entity on a failed review post and log it.
2. A superseded review still posts
The dispatcher knew at 20:53:20 that the run was superseded, and the run still posted 9.5 minutes
later against a head that had moved. There is no head-sha check in ReviewOrchestrator before
posting.
Re-reading the PR head before submitting, and abandoning the post when it has moved, would have
avoided this entirely: the coalesced run redid the work one second later regardless. It also stops
inline comments being resolved against a diff that changed underneath them, which is the more common
shape of this bug.
3. The no-comments path has no fallback
createReviewWithFallback retries without inline comments when a review carrying them is rejected.
When the review has no comments to drop, it rethrows, so the whole run is discarded — here ~100k
tokens and 9.5 minutes of wall clock, with an error surfaced to the user in place of a review.
Whatever the 422 turns out to be, a summary-only review that GitHub refuses should not cost the
entire generation. Falling back to an issue comment carrying the same body would preserve it.
Not reproducible on demand
#702 and #703 ran in the same window and completed normally (0 findings, COMMENT). Only #701 saw a
push land mid-review, which is what makes (2) the trigger and (1) the reason it cannot be confirmed.
A review on #701 was lost to a GitHub 422, and the logs cannot say why.
What happened
ready_for_review→ review starts on shaee78bfesynchronize→ head moves tod4389d2(a merge of main).ReviewDispatcherlogsCoalescing review for devops-thiago/ThrillhouseBot #701 — 1 superseded request(s), latest sha: d4389d2, and the in-flight run keeps goingPOST /pulls/701/reviews→ 422,ReviewPostException, user sees "review could not be completed"d4389d2starts from scratchEstablished from the logs and the API: the request carried no inline comments
(
createReviewWithFallbackthrowsReviewPostExceptiononly whenreq.comments().isEmpty(), and no"retrying without comments" warning was logged), the round had 0 new findings and 0 unresolved
previous, so this was
postNoIssuesReview. Not a force-push —ee78bfeis still a commit of the PR.Not a draft — converted to draft 19:05, back to ready 20:53:02. Not an over-long body —
CreateReviewRequestcaps it throughCommentBodyLimit.1. The 422 body is never logged
DefaultMicroprofileRestClientExceptionMappersurfaces the status and nothing else, so GitHub'smessage — the one thing that would name the cause — is discarded. The failure is undiagnosable after
the fact, which is why this issue can rank causes but not state one.
Two candidates remain: a
commit_id(ee78bfe) that is 9.5 minutes and one merge commit stale, orsomething specific to the APPROVE event. Worth noting for the second: every bot review on this
repository is
COMMENTED; none has ever landed asAPPROVED, so this plausibly was the firstAPPROVE attempt.
Fix: capture the response entity on a failed review post and log it.
2. A superseded review still posts
The dispatcher knew at 20:53:20 that the run was superseded, and the run still posted 9.5 minutes
later against a head that had moved. There is no head-sha check in
ReviewOrchestratorbeforeposting.
Re-reading the PR head before submitting, and abandoning the post when it has moved, would have
avoided this entirely: the coalesced run redid the work one second later regardless. It also stops
inline comments being resolved against a diff that changed underneath them, which is the more common
shape of this bug.
3. The no-comments path has no fallback
createReviewWithFallbackretries without inline comments when a review carrying them is rejected.When the review has no comments to drop, it rethrows, so the whole run is discarded — here ~100k
tokens and 9.5 minutes of wall clock, with an error surfaced to the user in place of a review.
Whatever the 422 turns out to be, a summary-only review that GitHub refuses should not cost the
entire generation. Falling back to an issue comment carrying the same body would preserve it.
Not reproducible on demand
#702 and #703 ran in the same window and completed normally (0 findings, COMMENT). Only #701 saw a
push land mid-review, which is what makes (2) the trigger and (1) the reason it cannot be confirmed.