reviewdog: fail to post review: pull request is closed or merged - how to fix
Fixes reviewdog failing with 'failed to post a review comment' when the pull request was already merged or closed (GitHub rejects reviews on closed PRs with a 422). Use when a reviewdog job with the github-pr-review reporter fails after a merge or close, or rerunning a merged PR's checks fails. Covers confirming PR state, restricting trigger types, guarding the job, and switching to the github-check reporter for post-merge findings. Not for reviewdog permission errors or diff-parse failures.
reviewdog: fail to post review: pull request is closed or merged - how to fix
TL;DR
The reviewdog CI job ran against a pull request that was already merged or closed, so GitHub rejects reviewdog's review submission with a 422 and reviewdog exits non-zero, failing the job. First confirm the PR state with gh pr view; if it is merged or closed, the findings are moot and rerunning will fail the same way. Then stop the job from running on closed PRs: restrict the workflow's pull_request activity types to open-PR events, or guard the reviewdog job with a PR-state condition. If you need findings posted even after merge or close, switch the reporter to github-check: the Checks API posts to the commit SHA and does not need an open PR.
The failure signature
reviewdog: failed to post a review comment: POST https://api.github.com/repos/[owner]/[repo]/pulls/[number]/reviews: 422 Validation Failed [{Resource:PullRequestReview Field:base Message:Pull request reviews may only be submitted on open pull requests}]You will usually see this in the CI log right after the linter output, and the reviewdog step (and the whole job) is marked failed. The linter itself ran fine; only the final review post failed.
The fix
Step 1 - Confirm the PR is actually closed or merged
gh pr view [number] --json state,mergedAtExpected output: something like {"state": "MERGED", "mergedAt": "..."} or {"state": "CLOSED", ...}. If it says OPEN, this is a different problem (check token scopes and the other reviewdog skills instead).
Step 2 - Check whether the findings already landed on an earlier run
Open the PR page and look for the reviewdog review posted by an earlier CI run. The diagnostics usually landed before the merge; a failed re-post adds nothing.
Expected output: either the review is already visible on the PR (nothing to do), or the PR merged so fast no run ever posted (continue to step 3).
Step 3 - Stop the workflow from triggering on closed PRs
The most common cause: on: [pull_request] fires on every activity type, including closed. Restrict it to open-PR activity types:
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]Expected output: future merges and closes no longer start a reviewdog run, so this failure cannot recur.
Step 4 - Guard the reviewdog job against a mid-run merge
Even with restricted types, a PR can merge while the job is queued or running (auto-merge, fast-moving PRs). Add a state guard on the reviewdog job:
jobs:
lint:
if: github.event.pull_request.state == 'open'
runs-on: ubuntu-latest
steps:
- run: reviewdog -f=rdjson -reporter=github-pr-review ...Note: this condition only works on pull_request events; push and workflow_dispatch events have no pull_request payload.
Expected output: the job is skipped instead of failing red when the PR merged before the review posted.
Step 5 - Switch reporter if you need findings on closed or merged PRs
If your workflow must run after merge or close (for example a post-merge check on pull_request_target, or findings you want attached to the merge commit), change -reporter=github-pr-review to -reporter=github-check. The Checks API posts to the commit SHA, which works fine on closed and merged PRs.
Expected output: findings appear as check-run annotations instead of inline review comments, and the job stays green after merge.
Use this when
- reviewdog logs
failed to post a review commentin a GitHub Actions job - The 422 message says pull request reviews may only be submitted on open pull requests
- The job failed after the PR was merged or closed, or someone hit Re-run jobs on a merged PR's check run
- Your reviewdog workflow triggers on bare
on: [pull_request](which includes theclosedactivity type)
Not for
reviewdog: annotation failed to post: resource not accessible by integration- that is a token permission problem, not a closed PR (see the reviewdog permissions skill)reviewdog: error: fail to parse diff: unexpected hunk header- that is a diff-format problem (see the reviewdog diff skill)- Reviews submitted through Octokit or the GitHub API directly by your own agent code - the Octokit "Pull request reviews may only be submitted on open pull requests" skill covers that path
- reviewdog never posting at all with no error - check the token (
REVIEWDOG_GITHUB_API_TOKEN) and reporter configuration first
Tool compatibility
- reviewdog: all recent versions (verified against reviewdog source, master 2026-10). The behavior is in the
github-pr-reviewreporter: it posts the review inFlushat the very end of the run via the GitHub CreateReview API, and treats a failed post as a fatal error. - GitHub REST API, pull request reviews endpoint; GitHub Actions. Only the
github-pr-reviewreporter needs an open PR;github-checkandgithub-pr-checkpost to the commit SHA instead.
Variant phrasings
reviewdog failed to post a review comment: 422 Validation Failed on merged PR
Same failure, one layer down. reviewdog does not retry or fall back for a closed-PR 422; it logs the line above and returns the error, so the step fails. The workflow-level guards in steps 3 and 4 are the fix.
reviewdog CI job fails after PR auto-merges
The race in its purest form: the PR auto-merged while the CI job was queued, and reviewdog's final review POST hit a merged PR. Step 4's state guard turns this from a red failure into a clean skip.
reviewdog run triggered by pull_request closed event
A bare on: [pull_request] includes the closed activity type, so merging or closing a PR starts a reviewdog run whose review post is guaranteed to fail. Restrict the activity types (step 3) unless you also switch to the github-check reporter.
Why it happens
GitHub's pull-request reviews endpoint requires the PR to be open at submit time. reviewdog collects findings during the run and submits them as one review in Flush, at the very end - so a merge or close that happens at any point during the run invalidates the final POST. The failure is timing, not permissions: the same job would have passed minutes earlier. reviewdog treats the failed post as fatal (there is no fallback for a non-permission 422, unlike the log fallback it uses for 403/404), which is why one closed PR turns a clean lint run into a red check.
Edge cases
- Auto-merge and fast merges: the guard in step 4 is the only reliable protection, because no trigger filter can prevent a merge that happens between queue time and post time.
- Merge queue: GitHub merge queue merges produce the same failure on reruns; the state guard covers it.
- Re-run jobs button: rerunning a merged PR's check run replays the whole job, including reviewdog's doomed review post. The guard turns it into a skip.
github-checktradeoffs: you lose inline review comments on the diff; annotations land on the check run instead, limited to 50 annotations per request and a 65535-character summary. Good for post-merge visibility, worse for line-level review discussion.- If you genuinely need a review comment on the closed PR anyway: reviews cannot be posted to closed PRs by any tool. Convert the findings into regular PR conversation comments (which still work on closed and merged PRs) or open a follow-up PR.
Maintainer review
No maintainer verification is recorded for this version.
This records the version a maintainer checked. It does not assert that the version is the latest upstream release.