## TL;DR
The review job started on an open PR and the PR closed before reviewdog posted. Check the PR state before the reviewdog step and skip the step when the PR is no longer open. This is a race, not a bug in your config.

## The error
```text
reviewdog: error: fail to post review: pull request is closed or merged: how to fix
```

## Steps
### 1. Confirm the race in the run logs
Check the timestamps: the workflow started while the PR was open and the merge or close landed mid-run.
Expected output: the PR state changed between job start and the reviewdog step.

### 2. Gate the reviewdog step on the PR being open
Add a condition to the reviewdog step so it only runs for open PRs:
```yaml
if: github.event.pull_request.state == 'open'
```
Expected output: the step is skipped cleanly instead of failing when the PR is closed.

### 3. Decide whether a skip should be silent
For required-status workflows, a skipped review step should not block the merge queue. Make sure the check reports success on skip or is not required.
Expected output: closed PRs do not leave the workflow red.

### 4. Re-run on an open PR to confirm nothing else broke
Expected output: reviewdog posts annotations normally when the PR is open.

## When to use
- reviewdog fails with pull request is closed or merged
- Auto-merge or fast human merges race the review job
- Scheduled or retry runs target PRs that closed since

## When not to use
- Permission errors posting reviews (the app lacks write access)
- Rate-limit failures
- Posting to the wrong PR number (a wiring bug, not a race)

## Tool compatibility
- reviewdog v0.14 and later; the post step behaves the same across versions
- GitHub Actions `if:` conditions on pull_request and pull_request_target events
- Same pattern works for any bot that posts reviews, not just reviewdog

## Variant phrasings
### reviewdog pull request not found
The PR or its head branch was deleted mid-run. Same family of race; gate on PR state and treat not-found as a skip.

### review job fails after the PR was merged by the queue
Merge queues close the PR the moment it merges. Either run the review before the queue step or accept the skip.

### scheduled review sweep fails on old closed PRs
Filter the sweep to open PRs before running the review step.

## Why it happens
CI jobs and PR state change independently. A review job that takes minutes can easily outlive the PR it is reviewing when auto-merge is on or a human merges quickly. reviewdog only discovers the PR is closed when it tries to post, which is the last step.

## Edge cases
- `pull_request_target` events: the state field is still available on the event payload; the same condition works.
- Draft PRs: they are open, so the step runs. If you want to skip drafts too, add a draft check to the condition.
- Reopened PRs: the gate re-runs on the reopen event and posts normally.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_StN0dJbgM_M0AN1CpgIXyw
