Skip to content

A dispatched review on a PR that edits .github/workflows/ always fails require-review, because claude-code-action refuses its token exchange #386

Description

@d-morrison

Observed repeatedly on #341 and written up only in a PR comment there, so filing it properly. It is a fourth mechanism, distinct from the three already in CLAUDE.md's "A PR fixing claude-code-review.yml (or claude.yml) itself can't self-verify before merge" section.

What happens

On a PR that touches any file under .github/workflows/, a workflow_dispatch-triggered review dies about 12 seconds in:

Attempt 1 failed: Workflow validation failed. The workflow file must exist and have identical content to the version on the repository's default branch. [...] This is expected when adding Claude Code workflows to new repositories or on PRs with workflow changes.

Action skipped due to workflow validation error.

The action then writes no execution output at all. upload-review-execution falls back to the temp path, finds nothing, and run-review-guard correctly reports:

::error::Claude review produced no execution output — treating as a failed review.

So claude-review fails, require-review fails, and the recorded cost is $0.0000.

Why the existing guards don't catch it

  • It is not a stub review. gha#185's retry path needs an execution file to inspect; here there is none, so the retry isn't even eligible.
  • It is not the Skip self-review when the PR edits this workflow guard. That one compares against the CALLER's own review-workflow path (claude-review.yml in this repo), so a PR editing claude.yml, _selftest.yml, or any other workflow sails straight past it and into this failure.
  • It is not the @v2-lag gap. The tag's position is irrelevant; this is the action's own App-token exchange refusing.

The asymmetry that makes it confusing: the pull_request-triggered review on the same head passes validation and reviews normally. So the PR can hold a genuine, complete verdict while require-review is red from a dispatched run — and every subsequent dispatch re-reddens it.

Why it compounds

Dispatched reviews are exactly what claude.yml fires when someone mentions the bot on such a PR. On #341 that produced four dispatched runs, each failing validation, each also cancelling the pull_request run that could have passed — because they share the claude-review-<PR> concurrency group. Recovering meant re-running the pull_request run once nothing else was in flight.

Suggested fix

Detect this specific signature — action skipped for workflow validation, zero execution output — and have run-review-guard skip rather than fail, the way it already skips for quota exhaustion. A dispatched review that was never allowed to start is not a failed review, and reporting it as one trains readers to ignore a red require-review, which is the check's whole value.

Worth pairing with a log line naming the cause, since the current error message ("produced no execution output") describes the symptom and gives no hint that a workflow-file change is why.

Not urgent

No correctness or security impact; the pull_request-triggered review still works, and the failure is loud rather than silent. The cost is a red required check that has to be diagnosed by hand each time, plus the cancellation collateral above.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions