Skip to content
Latchkey

gh run: Inspecting and Debugging Workflows From the Terminal

The two that save the most time: gh run view --log-failed prints only the failing step output, and gh run rerun --failed retries just the failed jobs instead of the whole workflow.

Reading a failed workflow in the browser means expanding groups and scrolling. gh run gets the same information into your terminal, where it can be grepped, and makes bulk analysis across runs possible at all.

Subcommands

CommandDoes
gh run listRecent runs, filterable by workflow and branch
gh run view <id>Summary of a run, with per-job status
gh run view <id> --logFull logs
gh run view <id> --log-failedOnly the failed steps. The one to use
gh run watch <id>Live progress, exits with the run status
gh run rerun <id>Re-run the whole workflow
gh run rerun <id> --failedRe-run only failed jobs
gh run cancel <id>Cancel
gh run download <id>Download artifacts

The commands worth memorising

Terminal
# the failing output only, no scrolling
gh run view --log-failed

# watch the current run and exit non-zero if it fails
gh run watch --exit-status

# re-run only what failed, with debug logging on
gh run rerun --failed --debug

# most recent failure for one workflow
gh run list --workflow=ci.yml --status=failure --limit 1 --json databaseId \
  --jq '.[0].databaseId' | xargs gh run view --log-failed

Bulk analysis across runs

Terminal
# which jobs fail most often?
gh run list --limit 100 --json databaseId --jq '.[].databaseId' |
while read -r id; do
  gh api "/repos/{owner}/{repo}/actions/runs/$id/jobs" \
    --jq '.jobs[] | select(.conclusion=="failure") | .name'
done | sort | uniq -c | sort -rn | head

# what share of runs are re-runs?
gh run list --limit 200 --json databaseId --jq '.[].databaseId' |
while read -r id; do gh api "/repos/{owner}/{repo}/actions/runs/$id" --jq '.run_attempt'; done |
awk '{t++; if ($1>1) r++} END {printf "re-run rate: %.1f%%\n", 100*r/t}'

Filtering runs

Terminal
gh run list --workflow=ci.yml
gh run list --branch=main --status=failure
gh run list --user=@me --limit 5
gh run list --event=pull_request
gh run list --json databaseId,conclusion,headBranch,createdAt

Using this in CI

CI checkouts are shallow and detached by default, which changes the answer this command gives you. Commands that read history, branch names, or tags need the checkout configured for it.

.github/workflows/ci.yml
- uses: actions/checkout@v4
  with:
    fetch-depth: 0   # history, tags, and git describe all need this

- run: |
    git rev-parse --is-shallow-repository   # expect false
    git rev-parse --abbrev-ref HEAD          # prints HEAD when detached

Frequently asked questions

How do I see only the failed logs of a GitHub Actions run?
gh run view --log-failed prints only the output of failed steps. Without an id it uses the most recent run, which makes it the fastest way to read a failure from the terminal.
Can I re-run only the failed jobs?
Yes: gh run rerun <id> --failed retries just the failed jobs rather than the whole workflow. Add --debug to enable step and runner debug logging on the retry.
How do I wait for a workflow to finish from the terminal?
gh run watch --exit-status streams progress and exits non-zero if the run fails, which makes it usable inside a script or a release checklist.
How do I find which jobs fail most often?
Loop gh run list over recent runs, pull each run jobs via gh api, filter to conclusion == "failure", and count by name. That ranking usually identifies the flaky job immediately.

Related guides

References

Run this faster and cheaper on Latchkey managed runners - self-healing included. Start free → 30-day trial · No credit card