GitHub Actions failures are easier to fix when you diagnose them in a consistent order. This guide shows how to inspect workflow evidence, isolate the failing layer, reproduce problems locally, check secrets and permissions, handle flaky tests, and track recurring failure patterns so the same incident does not keep returning.
Overview
A failed GitHub Actions run is an event, not a diagnosis. The visible error may be the first useful clue, but it is not always the underlying cause. A deployment step can fail because an earlier build produced the wrong artifact. A test can fail because a service was unavailable, not because the code changed. A workflow can stop before running any commands because its trigger, permissions, or referenced secret is incorrect.
Use a layered workflow for failed workflow diagnosis:
- Identify the exact run, job, and step that failed.
- Read the surrounding log context, not only the final error line.
- Classify the failure as configuration, dependency, code, environment, access, or infrastructure related.
- Reproduce the smallest possible failing operation locally or in a controlled test run.
- Apply one focused change and rerun the relevant check.
- Record the cause and prevention step for future maintenance.
This process is useful whether the workflow builds an application, runs security checks, publishes a package, or deploys to a cloud environment. For a broader checklist covering common build and automation errors, see the CI/CD pipeline failure troubleshooting checklist.
What to track
1. The failing workflow boundary
Start with the run URL, commit or pull request, branch, event type, job name, runner, and failed step. This prevents a common mistake: debugging a newer rerun or a different job than the one that originally failed. Note whether the failure occurred during checkout, dependency installation, compilation, testing, packaging, authentication, or deployment.
2. The complete log context
Expand the failed step and inspect the commands immediately before the error. Look for the working directory, selected runtime version, environment variables that are safe to display, cache messages, exit codes, and warnings. The last line often says only that a command returned a nonzero status. The useful explanation may appear several lines earlier.
Never paste secret values into debug output. If additional logging is needed, expose variable names and presence checks rather than their contents. Review workflow logs, uploaded artifacts, and annotations together; a test report or generated configuration file may explain a failure more clearly than the console output.
3. Runtime and dependency inputs
Track the language version, package-manager version, operating system image, lockfile state, dependency cache key, and relevant action versions. Differences between a developer workstation and the hosted runner frequently cause failures. A local environment may have a cached package, a global tool, a different shell, or a file-system behavior that the runner does not share.
When dependencies are involved, verify that the lockfile is committed, installation runs in the intended mode, and the cache is not hiding a stale or incomplete result. To test whether a cache is involved, perform a controlled run with the cache bypassed or temporarily changed rather than repeatedly rerunning the same state.
4. Secrets, variables, and permissions
Separate missing values from insufficient permissions. A missing secret may appear as an empty variable or an authentication error. A permissions problem may return an authorization response even when the token exists. Check the event context, repository or environment protection rules, job-level permissions, and whether the secret is available to the type of event that triggered the run.
Pull requests from forks and workflows triggered by different events can receive different access to secrets and tokens. Design workflows so that untrusted code does not receive sensitive credentials, and make the restricted path explicit instead of allowing a later deployment step to fail ambiguously.
5. Recurring failure signals
Keep a small record of failures over time. Useful fields include date, repository, workflow, branch, job, failure category, first suspected cause, confirmed cause, time to recovery, and prevention action. Track the failure rate by workflow and the number of reruns needed for a successful result. A single failure may be an isolated defect; repeated failures in the same step indicate a reliability or design issue.
Cadence and checkpoints
Debugging should happen immediately, but workflow maintenance benefits from a regular cadence. Use the following checkpoints without treating them as rigid deadlines.
During every failure
- Capture the run URL, commit, event, job, and failed step.
- Preserve relevant logs and test artifacts before rerunning repeatedly.
- Classify the failure before changing the workflow.
- Record whether a rerun passed without a code or configuration change.
- Document the confirmed cause and the smallest corrective action.
Weekly or after a busy release period
Review repeated failures, excessive reruns, cancelled jobs, and long-running steps. Look for patterns such as failures concentrated on one runner image, one repository, one dependency installation step, or one deployment environment. A workflow that eventually passes after several reruns may be masking a flaky test, a race condition, a service dependency, or an unstable test fixture.
Monthly
Inspect action references, runtime versions, cache behavior, required permissions, and the readability of workflow logs. Confirm that obsolete workarounds have not become permanent. Review whether jobs fail early with useful messages and whether repeated setup is a candidate for a reusable workflow or composite action.
Quarterly or before a major release
Run a controlled review of the complete delivery path: pull request checks, artifact creation, approval gates, deployment, and rollback or recovery steps. Verify that a new team member could identify the owner and first diagnostic action for each critical workflow. Pair this review with a pre-deployment checklist for safer production releases.
How to interpret changes
Not every increase in failures means the same thing. Interpret the pattern alongside recent changes to code, dependencies, workflow configuration, runner images, and external services.
One failure followed by clean reruns
This may indicate a transient dependency or infrastructure issue, but do not label it flaky without evidence. Check whether the rerun used the same commit and inputs. If the event repeats, add a specific observation to the failure record rather than relying on a generic “rerun fixed it” note.
Failures after a workflow edit
Compare the rendered workflow behavior before and after the change. Check indentation, expressions, job dependencies, shell assumptions, working directories, and whether a value moved from job scope to step scope. Validate expressions with safe test values and keep changes small enough that the cause remains visible.
Failures limited to pull requests
Compare the event payload and permission model with a push or manual run. Forked pull requests, protected environments, and restricted secrets can create intentional differences. Avoid weakening security merely to make a check pass. Instead, split untrusted validation from privileged publishing or deployment.
Failures that follow dependency or runtime updates
Compare lockfiles, tool versions, generated files, and platform-specific behavior. Reproduce the failing command with the same versions used by the runner. If a temporary pin is necessary, record why it exists and add a review date so it does not become invisible configuration debt.
For failures that reach cloud or infrastructure stages, distinguish application errors from deployment-state problems. A failed deployment may require checking credentials, target configuration, rollout status, or infrastructure drift rather than rebuilding the application. Keep infrastructure changes and application changes traceable; related Terraform drift detection guidance can help when the environment no longer matches its declared configuration.
When to revisit
Revisit this troubleshooting process whenever a workflow changes its trigger, permissions, runner, runtime, dependency strategy, deployment target, or secret source. These are high-risk points because they alter the conditions under which a previously reliable job runs.
Also return to the article on a monthly or quarterly cadence to review the failure tracker. Update the workflow when the same step requires repeated reruns, when diagnosis depends on undocumented local knowledge, or when a fix changes security boundaries. If an incident produces several follow-up tasks, use a structured postmortem action item tracker to assign owners and verify completion.
As a practical next step, choose one frequently failing workflow and create a short runbook containing its owner, inputs, required permissions, expected artifacts, common errors, and first three checks. Then make one preventive improvement: pin or update a dependency deliberately, improve an error message, add a deterministic test, validate a required variable, or split a privileged job from untrusted code. Recheck the workflow at the next review point and compare failure frequency, reruns, and recovery time with the baseline you recorded.