4.3 Troubleshooting Workflow Runs & Debug Logging
Key Takeaways
- Diagnostic debug logging is enabled across workflows by setting configuration variables or secrets ACTIONS_STEP_DEBUG=true and ACTIONS_RUNNER_DEBUG=true.
- Engineers can perform targeted re-runs from the GitHub UI: re-run all jobs, re-run failed jobs only (preserving upstream succeeded states), or re-run specific matrix permutations.
- Step annotations generated via workflow commands (::error::, ::warning::, ::notice::) surface directly in pull request diffs and workflow summaries for rapid triage.
- Workflow logs automatically redact registered secrets with *** and support dynamic runtime masking via ::add-mask::, while the web UI truncates very large step logs and asks you to download the full log archive instead.
- Common workflow failures originate from offline/mismatched runner labels, YAML syntax/indentation errors, fork PR secrets isolation, and invalid context evaluation.
Troubleshooting Workflow Runs & Debug Logging
When automated workflows fail in production CI/CD environments, engineers must rapidly diagnose root causes, isolate failing components, and remediate errors without introducing pipeline downtime. GitHub Actions provides powerful diagnostic logging controls, granular re-run capabilities, structured workflow annotations, and automated secret masking to streamline troubleshooting.
1. Systematic Troubleshooting Framework
When a workflow run fails or behaves unexpectedly, follow a structured four-stage diagnostic methodology:
2. Enabling Diagnostic & Debug Logging
By default, GitHub Actions suppresses internal runner agent communications and verbose step evaluations to keep logs clean. When standard console output is insufficient, you can activate two distinct debug logging channels.
1. Step Debug Logging (ACTIONS_STEP_DEBUG)
- Purpose: Prints extra verbose logging during step execution, including how environment variables are resolved, action input evaluation, shell script command traces, and detailed stdout/stderr streams.
- Activation: Set a repository secret, organization secret, or repository configuration variable named
ACTIONS_STEP_DEBUGwith the valuetrue.
2. Runner Diagnostic Logging (ACTIONS_RUNNER_DEBUG)
- Purpose: Logs runner agent internals, including runner registration, listener heartbeat polling, capability matching, job dispatch messages, and runner machine environment telemetry.
- Activation: Set a repository secret, organization secret, or repository configuration variable named
ACTIONS_RUNNER_DEBUGwith the valuetrue.
+-----------------------------------------------------------------------------+
| DEBUG LOGGING CONFIGURATION |
| |
| Setting Location: Settings -> Secrets and variables -> Actions |
| |
| Variable / Secret Name Value Diagnostic Output |
| ---------------------- ----- ----------------- |
| ACTIONS_STEP_DEBUG true Verbose step script traces |
| ACTIONS_RUNNER_DEBUG true Runner listener & host diagnostics |
+-----------------------------------------------------------------------------+
3. Enabling Debug Logging On-Demand via the UI
Instead of setting permanent configuration variables, you can enable debug logging temporarily when re-running a workflow. In the GitHub Actions run view, click Re-run jobs -> check the box "Enable debug logging" -> click Re-run jobs.
[!NOTE] When "Enable debug logging" is checked in the UI, GitHub Actions temporarily injects
ACTIONS_STEP_DEBUG=trueandACTIONS_RUNNER_DEBUG=trueinto that specific re-run execution without modifying repository settings.
3. Targeted Re-Run Strategies
In complex multi-job pipelines and matrix builds, executing an entire workflow from the beginning wastes compute minutes and delays feedback. GitHub Actions supports three granular re-run modes:
+-----------------------------------------------------------------------------+
| WORKFLOW RE-RUN STRATEGIES |
| |
| [1. Re-run all jobs] |
| Restarts the entire workflow DAG from scratch. |
| |
| [2. Re-run failed jobs] |
| Re-runs only jobs that failed or were cancelled, plus any downstream |
| dependent jobs. Succeeded upstream jobs are preserved! |
| |
| [3. Re-run specific matrix job] |
| Re-runs only the individual failed matrix slice (e.g., Windows Node 20)|
| while leaving all other successful combinations untouched. |
+-----------------------------------------------------------------------------+
Re-Running Failed Jobs in a DAG
Consider a pipeline with jobs: lint -> build -> test -> deploy.
lintandbuildsucceed.testfails due to an intermittent network glitch.deployis skipped.
When you select Re-run failed jobs:
lintandbuilddo not re-execute. Their previous outputs and uploaded artifacts remain available.testre-runs from scratch.- Upon
testsucceeding,deployexecutes automatically.
4. Log Inspection, Step Annotations & Masking
Step Annotations
Workflow commands formatted as ::error::, ::warning::, or ::notice:: generate highlighted UI callouts and inline annotations on pull request code diffs:
# Creating an error annotation targeting a specific file and line
echo "::error file=src/auth.ts,line=84,col=12::Missing JWT expiration check"
Downloading Complete Diagnostic Log Archives
For offline analysis or compliance audits, click the gear icon (⚙️) on the workflow run page and select Download log archive. This downloads a .zip archive containing:
- Individual
.txtstdout/stderr log files for every step in every job. - A dedicated
runner-diagnostic-logs/folder containing runner service communication traces (whenACTIONS_RUNNER_DEBUGis active).
Secret Masking & Log Truncation Rules
- Automatic Secret Masking: Any secret referenced via
${{ secrets.* }}is automatically registered in the runner's redaction filter. If printed to stdout, it is replaced with***. - Dynamic Runtime Masking (
::add-mask::): Tokens generated dynamically during script execution can be masked using:SESSION_TOKEN=$(vault-cli get-token) echo "::add-mask::$SESSION_TOKEN" - Log Truncation in the Browser: GitHub does not publish a numeric log-size limit, but the web UI will not render an unbounded step log. A very large step is displayed with its head only and the notice "This step has been truncated due to its large size. Download the full logs from the menu once the workflow run has completed." The full output is still in the downloadable archive - it is a rendering limit, not data loss.
- Live-Log Lag on Noisy Steps: Streaming logs for a high-volume step can fall behind, so the tail of the output may only become visible after the job completes. When a failure message is being buried, fix it at the source: quiet verbose tooling, or write detailed diagnostics to an artifact with
actions/upload-artifactinstead of to stdout.
5. Common Workflow Execution Errors & Remediation
| Failure Symptom | Underlying Root Cause | Remediation Procedure |
|---|---|---|
Workflow stuck in Queued indefinitely | No online self-hosted runner matches the requested runs-on labels, or organization runner group limits reached. | Verify self-hosted runner service is running (./run.sh); check label typos (e.g., [self-hosted, linux, arm64]). |
Invalid workflow file: Unexpected symbol | YAML indentation syntax error or unquoted expression special characters (:, {, }, *). | Wrap expressions containing colons or braces in quotes (e.g., name: 'Build: ${{ matrix.os }}'). |
| Secrets resolve to empty strings in PR | Workflow triggered by pull_request from an external fork repository (secrets disabled by design). | Use pull_request_target for trusted metadata automations, or require repository collaborator approval before running fork workflows. |
Context access error: Property 'outputs' not found | Downstream job references upstream output without declaring needs: <job_id> or upstream job omitted top-level outputs: mapping. | Ensure caller job defines needs: and upstream job explicitly maps step outputs under outputs:. |
Which configuration variables or repository secrets must be set to true to enable verbose runner diagnostic logging and step execution debug traces across GitHub Actions runs?
A complex workflow contains four sequential jobs: compile -> unit-test -> e2e-test -> publish. During a pipeline run, compile and unit-test complete successfully, but e2e-test fails due to a temporary database timeout. What occurs when the engineer clicks 'Re-run failed jobs' in the GitHub Actions UI?
A bash script inside a workflow step dynamically requests an ephemeral session token from an internal vault server. How can the developer ensure that any subsequent occurrences of this token are automatically masked as *** throughout all workflow console logs?