Skip to content

Fix "Waiting for status to be reported" on GitHub

Updated

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

CauseHow to recognize itFix
A paths, paths-ignore or branches filter skipped the workflowThe workflow has a filter, and this pull request's files or branch fall outside itMove the filter into the job
[skip ci] in the commit messageThe latest commit's message contains itPush a commit without it
The job's name changedThe required name matches no job, as after a renameUpdate the name in the branch's rule
A matrixEach combination reports its own check, such as test (20), not testRequire one summary job
A merge queueThe check passed on the pull request, and waits in the queueAdd the merge_group trigger

GitHub's troubleshooting page 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:

.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:

.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:

.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:

.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 asks whether this exact code already passed, so the workflow can start every time with no filter to keep up to date:

.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. The job still starts and installs, so hushrun saves the check's minutes, not the job's. In CI has the setup.

Markdown