Articles
Debug GitHub Actions from Your Terminal with gh
Most CI failures don't require the Actions UI at all. The gh CLI gives you the core loop from your terminal: find the broken run, read the failure, retry it, and watch it live.
Debug GitHub Actions from Your Terminal with gh
If your GitHub Actions debugging workflow starts with opening three browser tabs, it is probably slower than it needs to be.
Most CI failures do not require the Actions UI at all. The gh CLI gives you the core loop from your terminal: find the broken run, read the failure, retry it, and watch it live. Once you get used to it, going back to the browser feels clumsy.
Find the run
gh run list --limit 10
Start here. This shows recent runs, their status, and what triggered them.
If a workflow has been stuck in queued forever, you will see it immediately. If you want to script against the output, add --json and skip the copy-paste routine entirely.
Read only what failed
gh run view <run-id> --log-failed
This is the command I was missing.
You do not always need the full log dump. You usually need the failing step. --log-failed cuts straight to the useful part, which matters a lot once your workflow grows past a handful of jobs.
If you do need everything, switch to --log. If you are debugging a matrix build, pipe the output into grep and keep moving.
Retry only the broken part
gh run rerun <run-id> --failed
This reruns only the jobs that failed, plus anything they depend on. That is usually what you want.
If the failure came from a flaky test, a registry timeout, or some other transient CI nonsense, rerunning the entire workflow is just wasted time and compute.
One gotcha: you cannot rerun a workflow while it is still in progress. The CLI can return an error that makes it sound like the workflow file is invalid. In practice, it often just means the run has not finished yet.
If you want to rerun one specific job, get the correct ID first:
gh run view <run-id> --json jobs --jq '.jobs[] | {name, databaseId}'
Use databaseId with --job. Do not trust yourself to grab a random number from the web UI and hope it matches what the CLI expects.
Watch it live
gh run watch <run-id>
This streams the run as it happens. It is the closest thing to tail -f for Actions, and it is a lot nicer than refreshing the browser every 20 seconds.
If you live in the terminal already, this feels like the missing piece.
Trigger a run without pushing a commit
gh workflow run <workflow-file>.yml --ref <branch>
If a workflow supports workflow_dispatch, use it. It is one of the simplest ways to test workflow changes without creating throwaway commits just to poke CI.
If your workflow does not expose workflow_dispatch, that is worth fixing. Manual triggers make debugging easier and demos cleaner.
The 403 that wastes too much time
A surprising number of Actions failures come down to one thing: GITHUB_TOKEN does not have the permission your workflow needs, and the error message is usually less clear than it should be.
If your workflow needs to write to the repository or update a pull request, declare permissions explicitly:
permissions:
contents: write
pull-requests: write
Do not rely on defaults and then act surprised when a write fails halfway through automation. Ask for the minimum you need, on purpose.
The loop I actually use
gh run list # find the run
gh run view <run-id> --log-failed # read the failure
gh run rerun <run-id> --failed # retry only what broke
gh run watch <run-id> # follow the rerun live
That is enough for a big chunk of day-to-day Actions debugging. The browser still has its place, but it does not need to be your default.
Full reference: cli.github.com/manual/gh_run
About the Author: Andrea Griffiths is a Senior Developer Advocate at GitHub, where she helps engineering teams adopt and scale developer technologies. She's passionate about making technical concepts accessible—to both humans and AI agents. Connect with her on LinkedIn, GitHub, or Twitter/X. · Read in Spanish · 阅读中文版