Debugging Pipelines

Learn how to debug GitLab CI/CD pipelines systematically. From CI Lint and pipeline editor validation to debug tracing, variable verification, and dependency checks, find and fix pipeline failures faster.

Debugging Troubleshooting GitLab CI/CD
Why Systematic Debugging Matters

Pipeline failures are inevitable. A missing variable, a typo in a script, a dependency that changed version — any of these can break a pipeline that worked yesterday. The difference between a team that recovers quickly and one that struggles is not the absence of failures; it's the presence of a systematic approach to debugging. Random trial and error wastes hours; a structured methodology finds the root cause in minutes.

GitLab provides several tools for this. The CI Lint tool validates syntax before you commit. The pipeline editor simulates pipeline creation, catching logic errors in rules and needs. CI_DEBUG_TRACE enables verbose logging when a job fails mysteriously. Variable verification confirms that the values your job sees are the values you expect. Each tool addresses a different class of problem, and knowing when to use each is the key [citation:1][citation:7].

The most common debugging mistake is jumping to conclusions. A job fails with "command not found," so you assume the image is wrong. But the real cause might be a missing before_script, a variable that didn't expand, or a dependency that failed to install. The systematic approach is to isolate: check the configuration, then the environment, then the script, then the dependency. Narrowing the problem space is faster than guessing.

Core Principle: Debugging is a process of elimination. Start with the tools that catch the most common problems (CI Lint), then move to runtime diagnostics (debug trace, variable checks), then to deeper investigation (dependencies, environment).

CI Lint

Validates syntax and simulates pipeline creation. Catches YAML errors, invalid keywords, and logic issues before commit.

Pipeline Editor

Live syntax validation, visualization, and full configuration view. The primary editing experience.

CI_DEBUG_TRACE

Enables verbose logging. Shows commands, variables, and environment. Use sparingly.

Variable Verification

Check which variables exist and their values. Many failures are variable mismatches.

Dependency Checks

Verify tool versions, pin critical dependencies, and check that installs succeeded.

Root Cause Analysis

GitLab Duo can analyze failed job logs and suggest fixes (Ultimate).
CI Lint and Pipeline Editor

The CI Lint tool is the first line of defense against pipeline failures. It validates the syntax of your .gitlab-ci.yml file against the GitLab CI/CD schema, catching typos, invalid keywords, and structural errors before you commit. When the project has a .gitlab-ci.yml file, CI Lint can also simulate pipeline creation, which validates not just syntax but also logic — checking that rules, needs, and include statements produce the expected pipeline [citation:1][citation:7].

The pipeline editor is the primary place to edit CI/CD configuration. It provides live syntax validation as you type, a visualization of the pipeline graph, and a "Full configuration" view that shows the merged result of all include statements. This is invaluable for debugging: if a job is missing or has unexpected configuration, the full configuration view shows exactly what GitLab sees, including any included templates [citation:5].

The "Validate" tab in the pipeline editor simulates a pipeline creation for a specific branch and pipeline source. This catches issues that syntax validation misses: a rule that never matches, a needs dependency on a job that doesn't exist, or a workflow rule that blocks the pipeline entirely. If the simulated pipeline is empty or missing expected jobs, the problem is in the configuration logic, not in the job execution [citation:5].

# CI Lint usage # Build > CI Lint # Paste your .gitlab-ci.yml content # Click "Validate" # Or use "Simulate pipeline creation" for deeper validation # Pipeline editor # Build > Pipeline editor # - Edit tab: live syntax validation # - Visualize tab: pipeline graph # - Full configuration tab: merged config with includes # - Validate tab: simulate pipeline creation # Common syntax errors caught by CI Lint: # - Invalid keyword (e.g., "stages" misspelled) # - Wrong indentation # - Missing required fields (script for jobs) # - Invalid variable syntax # - Duplicate job names # Common logic errors caught by simulation: # - rules that never match # - needs on non-existent jobs # - workflow:rules blocking all pipelines # - include paths that don't exist # Example: validate before commit # 1. Open Pipeline editor # 2. Make changes in Edit tab # 3. Check syntax status at top (valid/invalid) # 4. Go to Validate tab # 5. Select branch and source # 6. Click "Validate pipeline" # 7. Review the simulated pipeline # If validation fails: # - Read the error message carefully # - Check the line number (if provided) # - Compare with GitLab CI/CD reference # - Use Full configuration to see merged result
CI Lint Best Practices:
  • Validate syntax before every commit — catches the most common errors
  • Use the simulation feature to test logic, not just syntax
  • Check the Full configuration view when includes are involved
  • If a pipeline runs but jobs are missing, use simulation to debug rules
CI_DEBUG_TRACE

When a job fails and the log doesn't explain why, CI_DEBUG_TRACE enables verbose logging. Setting this variable to true makes the runner print every command it executes, along with the environment variables available to the job. This is the fastest way to see exactly what the runner is doing and what values it's using [citation:4].

The variable is powerful but dangerous. The debug trace includes all environment variables, which may include secrets. If a sensitive variable is not masked, it will appear in the log. For this reason, access to debug logging is restricted to users with Developer role or higher. It's also why you should never set CI_DEBUG_TRACE as a runner-level variable — the runner doesn't check permissions, so anyone with access to job logs could see the trace [citation:4].

Use CI_DEBUG_TRACE as a temporary diagnostic, not a permanent setting. Enable it on a specific job (not globally), run the pipeline, inspect the log, then disable it. If you need ongoing verbosity for a specific tool, add --verbose to that tool's command in the script instead of enabling full debug tracing. This limits the noise and the security exposure.

# Enable debug trace for a specific job debug_job: variables: CI_DEBUG_TRACE: "true" script: - echo "This will produce verbose output" # Or enable for the entire pipeline (temporarily) # Settings > CI/CD > Variables # Add CI_DEBUG_TRACE = true # Disable after debugging # Warning: debug trace shows all variables # Ensure sensitive variables are masked # Settings > CI/CD > Variables > Masked: ✓ # CI_DEBUG_TRACE output includes: # - Every command executed # - Environment variables # - Shell expansions # - Exit codes # Do NOT set CI_DEBUG_TRACE on the runner # Runner-level debug trace bypasses permission checks # and is visible to all users with job log access # Better: use --verbose for specific tools script: - npm test -- --verbose - docker build --progress=plain . # Or use a debug variable with default empty variables: DEBUG_VARS: "" script: - my-test-command $DEBUG_VARS /test-dirs # Set DEBUG_VARS=--verbose when running manually
CI_DEBUG_TRACE Security: