# Fix "Waiting for status to be reported" on GitHub

A pull request shows **Expected — Waiting for status to be reported** when a required check hasn't reported on its latest commit. Usually the check's workflow never started, so GitHub waits for a result that won't come, and the pull request can't merge.

## Find the cause

| Cause | How to recognize it | Fix |
|---|---|---|
| A `paths`, `paths-ignore` or `branches` filter skipped the workflow | The workflow has a filter, and this pull request's files or branch fall outside it | [Move the filter into the job](#filter-in-the-job) |
| `[skip ci]` in the commit message | The latest commit's message contains it | Push a commit without it |
| The job's name changed | The required name matches no job, as after a rename | Update the name in the branch's rule |
| A matrix | Each combination reports its own check, such as `test (20)`, not `test` | [Require one summary job](#summary-job) |
| A merge queue | The check passed on the pull request, and waits in the queue | [Add the `merge_group` trigger](#merge-queue) |

[GitHub's troubleshooting page](https://docs.github.com/en/pull-requests/how-tos/merge-and-close-pull-requests/troubleshooting-required-status-checks) puts the rule this way: avoid requiring workflows that can be skipped.

## Move the filter into the job

A `paths` filter on the workflow stops it from starting, so nothing reports. A job skipped by `if:` is different: GitHub reports it as a success. Start the workflow every time and decide in the job:

```yaml title=".github/workflows/ci.yml"
on:
  pull_request:

jobs:
  changes:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: read
    outputs:
      code: ${{ steps.filter.outputs.code }}
    steps:
      - uses: dorny/paths-filter@v4
        id: filter
        with:
          filters: |
            code:
              - "src/**"
              - "package-lock.json"

  test:
    needs: changes
    if: needs.changes.outputs.code == 'true'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - run: npm ci
      - run: npm test
```

On a pull request that changes only documentation, `test` is skipped and reports success, so the pull request can merge.

There's a trap here. A job whose dependency fails is skipped too, and GitHub says that skip may not block merging. If `changes` fails, `test` can look fine with nothing tested. A summary job closes that gap.

## Require one summary job

Add a job that always runs and fails when any other job failed, and make it the only required check:

```yaml title=".github/workflows/ci.yml"
  ci-ok:
    needs: [changes, test]
    if: always()
    runs-on: ubuntu-latest
    steps:
      - if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')
        run: exit 1
```

- `if: always()` is what makes this safe. Without it, `ci-ok` is skipped when a job it needs fails, and a skipped check may let the pull request through.
- Skipped jobs don't fail it, so a filtered job doesn't block a merge.
- The required list stays one name, whatever you add to the matrix or rename.

## Report in the merge queue

Checks in a merge queue report on a temporary merge commit, and `pull_request` doesn't start a workflow there. A workflow that's required in the queue needs the `merge_group` trigger too:

```yaml title=".github/workflows/ci.yml"
on:
  pull_request:
  merge_group:
```

In the queue, `dorny/paths-filter` reads the changes with git, not GitHub's API. The `changes` job above then needs a checkout, and the permission for it:

```yaml title=".github/workflows/ci.yml"
  changes:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: read
    outputs:
      code: ${{ steps.filter.outputs.code }}
    steps:
      - uses: actions/checkout@v7
      - uses: dorny/paths-filter@v4
        id: filter
        with:
          filters: |
            code:
              - "src/**"
              - "package-lock.json"
```

## Don't remove the requirement

Taking the check off the required list unblocks the pull request, and every later one, with nothing tested. If you need to merge past it once, and your rule allows bypassing, an admin can do that for one pull request and leave the rule in place.

## With hushrun

A path filter asks what changed. [`hushrun run`](https://hushrun.com/docs/run.md) asks whether this exact code already passed, so the workflow can start every time with no filter to keep up to date:

```yaml title=".github/workflows/ci.yml"
jobs:
  test:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      id-token: write
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
        with:
          node-version: 22
      - run: npm ci
      - run: npm test
```

Here `npm test` is wrapped once in `package.json`, as `hushrun run -- vitest run`. A skip exits 0, so the required check always reports. A change anywhere in the repository runs the check again, unless you narrow it with [scopes](https://hushrun.com/docs/run.md#monorepos). The job still starts and installs, so hushrun saves the check's minutes, not the job's. [In CI](https://hushrun.com/docs/ci.md) has the setup.

## Related

- [Run GitHub Actions only when files change](https://hushrun.com/docs/guides/github-actions-run-when-files-change.md)
- [Skip CI when the code hasn't changed](https://hushrun.com/docs/guides/skip-ci.md)
- [Why CI runs the same tests twice](https://hushrun.com/docs/guides/duplicate-ci-runs.md)
