How to Force Stop a GitHub Actions Workflow
Introduction
Sometimes a GitHub Actions workflow keeps running forever. For example, a deployment job does not exit, the runner crashes, a Docker child process does not stop, or a self-hosted runner becomes unresponsive. In these cases, the normal cancel action may not work, so you need a force stop method.
Solution
Option 1: Cancel it from the GitHub web UI
This is the simplest way.
- Open the repository Actions page
- Open the running workflow
- Click
Cancel workfloworCancel jobs - If normal cancellation does not work, click
Force cancel workflow
Force cancel workflow is useful when the workflow is stuck and cannot exit normally.
Option 2: Cancel it with GitHub CLI
If you already have GitHub CLI installed, using the command line is usually faster.
First, list the current workflow runs:
gh run list
The output is usually similar to this:
STATUS TITLE WORKFLOW BRANCH
running deploy CI main
Normal cancel:
gh run cancel <run-id>
For example:
gh run cancel 26392735720
If that does not work, use force cancel:
gh run cancel 26392735720 --force
Option 3: Force cancel it with the API
GitHub Actions provides a REST API to force cancel a workflow run.
The endpoint format is:
POST /repos/{owner}/{repo}/actions/runs/{run_id}/force-cancel
For example, if the page URL is:
https://github.com/openHacking/PyDeskUI/actions/runs/26392735720/job/77686565248
Then:
OWNERisopenHackingREPOisPyDeskUIRUN_IDis26392735720- The trailing
77686565248is thejob id, not therun id
So the API URL is:
https://api.github.com/repos/openHacking/PyDeskUI/actions/runs/26392735720/force-cancel
Full example:
curl -L \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer <TOKEN>" \
https://api.github.com/repos/openHacking/PyDeskUI/actions/runs/26392735720/force-cancel
If GitHub CLI is already authenticated on your machine, this command is usually easier:
gh run cancel 26392735720 --force
Option 4: Kill a stuck self-hosted runner
If the repository uses a self-hosted runner, sometimes the real problem is not the workflow itself but the runner process. In that case, even Force cancel workflow may not stop it.
You can go to the runner machine and kill the related process directly.
First, find the process:
ps aux | grep Runner
Or:
ps aux | grep actions
Then force kill it:
kill -9 <pid>
If your runner is inside Docker, you can kill the container instead:
docker ps
docker kill <container-id>
Extra Tip
If the same workflow often gets queued repeatedly and old runs block the runner, you can add concurrency control to the workflow so that newer runs automatically cancel older ones:
concurrency:
group: deploy-${{ github.ref }}
cancel-in-progress: true
This reduces the chance of old deployment jobs piling up and needing manual cleanup.

Comments