A New Collection of Thoughtful Learning Apps — Now Available on iOS & Android

Image
I’m excited to share a set of mobile apps I’ve recently completed and published on both the Google Play Store and the Apple App Store. These apps are designed with a simple goal in mind: to make meaningful, structured content more accessible, whether you’re studying theology or improving your English vocabulary. 📱 Now Available on Both Platforms All apps are live and available for download: Google Play Developer Page: https://play.google.com/store/apps/dev?id=5835943159853189043 Apple App Store Developer Page: https://apps.apple.com/ca/developer/q-z-l-corp/id1888794100 📖 Theology & Confession Study Apps For those interested in Reformed theology and classical Christian teachings, I’ve developed a series of apps that present foundational texts in a clean, focused reading format: The Belgic Confession Canons of Dort Heidelberg Catechism Westminster Shorter Catechism Each app is designed to provide a distraction-free experience, making it easier to read, reflect, and revisit these im...

Why Your GitHub PR Checks Get Stuck Forever and The Fix

Why Your GitHub PR Checks Get Stuck Forever and The Fix

TL;DR

If you open a pull request against one branch (for example, develop) and later retarget it to another branch that has GitHub rulesets requiring specific workflows (for example, main), the newly required checks can become stuck showing:

Expected — Waiting for workflow to run

Not queued. Not in progress. Just permanently stuck, with no workflow run ever created for that check.



The fix is simple: push a new commit (even an empty commit). However, understanding why this happens can save a lot of debugging time.


The Setup

We use an organization-level GitHub ruleset to enforce that certain workflows must run and pass before a PR can be merged into protected branches.

Example:

target: branch

conditions:
ref_name:
include:
- "~DEFAULT_BRANCH"

rules:
- type: workflows
parameters:
workflows:
- repository_id: <container-build-repo-id>
path: .github/workflows/ruleset_build.yaml
ref: refs/tags/v1

The reusable workflow itself looks like:

on:
workflow_call:

pull_request:
branches:
- main
- master

This is a common "golden path" pattern:

  • Workflows live in a central repository.
  • Application repositories consume them through reusable workflows.
  • Rulesets make them mandatory for protected branches.

This keeps CI/CD governance centralized and consistent.


What Happened

Step 1

A PR was opened against develop.

Since develop was not covered by the ruleset, no required workflow checks were enforced.

Step 2

A few minutes later, the PR was retargeted to main using GitHub's Edit → Change Base Branch functionality (or via the Pull Request API).

Step 3

GitHub immediately recognized that main is protected by the ruleset and added the required checks:

  • 🏗 Build → Expected
  • 🛡 Security Scan → Expected

Step 4

Nothing happened.

The checks remained in the following state indefinitely:

Expected — Waiting for workflow to run

No jobs appeared in the Actions tab.

No workflow execution started.

No progress was ever made.


Diagnosing the Problem

The GitHub UI is misleading in this scenario.

"Waiting for workflow to run" sounds like something is queued and will eventually execute.

In reality, nothing is scheduled.

We confirmed this using the GitHub API:

gh api repos/<org>/<repo>/commits/<sha>/check-runs

Output:

{
"total_count": 0,
"check_runs": []
}

No check-runs existed.

Checking check suites produced the same result:

gh api repos/<org>/<repo>/commits/<sha>/check-suites

Only unrelated suites appeared. No suites existed for the required ruleset workflows.


Things We Ruled Out

We systematically eliminated the usual causes:

  • ❌ GitHub outage or incident
  • ❌ Missing or broken workflow tag reference (refs/tags/v1)
  • ❌ Invalid workflow YAML
  • ❌ Missing repository custom properties
  • ❌ Actions disabled
  • ❌ Permission issues

Everything looked healthy.


The Clue

The breakthrough came from inspecting the PR timeline via GraphQL:

gh api graphql -f query='
{
repository(owner: "...", name: "...") {
pullRequest(number: 970) {
timelineItems(
first: 20,
itemTypes: [BASE_REF_CHANGED_EVENT]
) {
nodes {
... on BaseRefChangedEvent {
previousRefName
currentRefName
createdAt
}
}
}
}
}
}'

Result:

{
"previousRefName": "develop",
"currentRefName": "main",
"createdAt": "..."
}

The PR's base branch had changed several minutes after creation.


Root Cause

GitHub Actions workflows triggered by pull_request events only run for specific PR lifecycle events, such as:

  • opened
  • synchronize
  • reopened
  • ready_for_review

A base branch change is not one of those events.

This creates a split-brain situation between two GitHub subsystems.

Ruleset Engine

When the base branch changes:

develop -> main

the ruleset engine immediately re-evaluates branch protection requirements.

It determines:

This PR now requires Container Build and SAL Scan.

The checks are added to the merge requirements instantly.

Actions Dispatcher

However, GitHub Actions does not dispatch a new pull_request event when the base branch changes.

Therefore:

  • No workflow run is created.
  • No checks start.
  • No check-runs exist.
  • No check-suites exist.

The required checks now exist only as expectations.

Nothing is available to satisfy them.

The PR becomes stuck in a state that cannot resolve itself.


The Fix

The solution is to trigger a new PR event.

The easiest method is an empty commit:

git commit --allow-empty -m "Retrigger CI checks"
git push

This generates a:

pull_request: synchronize

event.

GitHub Actions then dispatches the required workflows, and the checks begin running normally.

Alternative

Closing and reopening the PR also works because GitHub fires a fresh PR lifecycle event.

However, this is generally less desirable because it can affect review workflows, notifications, and UI state.

An empty commit is usually the cleanest option.


Key Takeaways

1. "Expected" Does Not Mean "Queued"

If a check shows:

Expected — Waiting for workflow to run

for more than a few minutes, verify that an actual workflow run exists.

Check:

gh api repos/<org>/<repo>/commits/<sha>/check-runs

and

gh api repos/<org>/<repo>/commits/<sha>/check-suites

If neither contains the required workflow, waiting longer will not help.


2. Base Branch Changes Do Not Retrigger Workflows

Changing:

develop -> main

updates branch protection and rulesets immediately, but does not trigger pull_request workflows.

Always assume a follow-up push is required after retargeting an existing PR.


3. Rulesets + Reusable Workflows Have This Edge Case

Organizations that use:

  • Centralized reusable workflows (workflow_call)
  • Organization-level rulesets
  • Protected branches

are particularly likely to encounter this behavior.

Common scenarios include:

  • Switching a PR from develop to main
  • Branch strategy changes
  • Renamed default branches
  • Deleted or replaced release branches

The ruleset updates immediately, but Actions remains unaware until another PR event occurs.


Final Recommendation

Whenever a PR's base branch is changed to a branch with different required checks:

git commit --allow-empty -m "Retrigger required workflows"
git push

Treat this as standard practice.

It immediately forces GitHub Actions to re-evaluate the PR, run the newly required workflows, and satisfy the updated ruleset requirements.

❤️ Support This Blog


If this post helped you, you can support my writing with a small donation. Thank you for reading.


Comments

Popular Posts

A New Collection of Thoughtful Learning Apps — Now Available on iOS & Android

2023, New Start! New AdSense Account! New Earnings!

Swagger annotations for API that allows downloading files as zip