CI/CD

YAML Syntax Errors in CI/CD: A Field Guide to the Ones That Waste the Most Time

A gallery of real broken YAML snippets from GitHub Actions and GitLab CI with side-by-side fixes. Stop losing pipeline runs to indentation, tabs, and multiline string gotchas.

D

Daxtack Team

Engineering

8 min read

YAML is the configuration language of modern CI/CD — and it's uniquely terrible at telling you what you did wrong. A misplaced space, a tab character, or a missing colon can break your entire pipeline with an error message that points to the wrong line.

This isn't a YAML tutorial. It's a field guide to the specific YAML mistakes that waste the most engineering time in CI/CD pipelines, with real broken examples and their fixes shown side by side.

Why YAML Is Uniquely Bad for This

Most programming languages have compilers or interpreters that give you precise error messages with line numbers. YAML has none of this:

  • Whitespace-sensitive — indentation determines structure, but there's no visual difference between 2 spaces and 3 spaces
  • No compiler feedback loop — you push, wait for CI to start, and then find out your YAML is broken. The feedback loop is minutes, not milliseconds
  • Error messages are misleading — YAML parsers often report errors at the point where the consequence of the mistake is detected, not where the mistake actually is
  • Platform-specific extensions — GitHub Actions YAML isn't the same as GitLab CI YAML. Valid syntax for one may be invalid for the other

Mistake 1: Indentation Misalignment

The #1 YAML mistake in CI/CD. Off-by-one indentation changes the meaning of your entire pipeline:

Broken:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install deps
        run: npm ci
       - name: Test        # ← 7 spaces instead of 8
        run: npm test

Fixed:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install deps
        run: npm ci
      - name: Test         # ← 6 spaces, aligned with other list items
        run: npm test

The error message won't say "indentation wrong on line 8." It'll say something like mapping values are not allowed in this context and point to a completely different line.

Mistake 2: Tabs vs. Spaces

YAML does not allow tab characters for indentation. Period. But many editors insert tabs by default, and tabs are invisible in most UIs.

The trap: You copy a YAML snippet from a blog post that used tabs. It looks identical to properly-indented YAML. Your pipeline fails with a cryptic parser error.

How to detect:

# Find tabs in your CI config
grep -P '\t' .github/workflows/*.yml
cat -A .github/workflows/ci.yml | grep '\^I'

How to prevent:

  • Add "editor.insertSpaces": true to your VS Code settings
  • Add an .editorconfig file with indent_style = space
  • Use a pre-commit hook that rejects tabs in YAML files

Mistake 3: Missing Required Keys

Both GitHub Actions and GitLab CI have required keys that produce confusing errors when absent:

GitHub Actions — missing run or uses:

# Broken: step has a name but no action
- name: Build the project
  # Missing: run: npm run build

Error: Every step must define a 'uses' or 'run' key

GitLab CI — missing script key:

# Broken
build:
  stage: build
  # Missing: script: key
  image: node:20

Error: jobs:build config should implement a script: or a trigger: keyword

This one catches people who are used to GitHub Actions syntax trying to write GitLab CI config, or vice versa.

Mistake 4: Multiline String Gotchas

YAML has multiple ways to write multiline strings, and each behaves differently. This is where even experienced engineers trip up:

Pipe (|) — preserves newlines:

- name: Multi-command step
  run: |
    echo "Line 1"
    echo "Line 2"
    npm test

Greater-than (>) — folds into a single line:

# This becomes ONE line: "echo hello echo world"
- name: Broken multi-command
  run: >
    echo hello
    echo world

The > block scalar folds newlines into spaces. If you want multiple shell commands, you need |, not >. Using > will concatenate your commands into one nonsensical string.

Common trap — indentation inside multiline blocks:

# Broken: first line of block must be indented relative to the key
- run: |
echo "this will fail"  # ← not indented under run:
# Fixed
- run: |
    echo "this works"   # ← indented under run:

Mistake 5: Anchors and Aliases Gone Wrong

YAML anchors (&) and aliases (*) let you reuse configuration. They're powerful but fragile:

Broken — alias before anchor:

# Can't use *defaults before defining &defaults
deploy:
  <<: *defaults
  script: ./deploy.sh

.base: &defaults
  image: node:20
  before_script:
    - npm ci

Fixed — anchor must come first:

.base: &defaults
  image: node:20
  before_script:
    - npm ci

deploy:
  <<: *defaults
  script: ./deploy.sh

Note: GitHub Actions doesn't support YAML anchors at all. This is GitLab CI-specific.

Prevention: Validate Before You Push

The single best habit for avoiding YAML errors is validating locally before pushing:

Tools:

  • GitLab CI Lint — built into GitLab at /-/ci/lint. Paste your .gitlab-ci.yml and it validates both syntax and CI semantics
  • yamllint — catches formatting issues: pip install yamllint && yamllint .github/workflows/
  • VS Code YAML extension — real-time schema validation. Install the Red Hat YAML extension and add schema mappings for your CI platform
  • actionlint — purpose-built for GitHub Actions. Checks syntax, expression types, and action versions: brew install actionlint && actionlint

Pre-commit hook example:

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/adrienverge/yamllint
    rev: v1.35.1
    hooks:
      - id: yamllint
        args: [-d, relaxed]

Syntax errors are the easy case — the pipeline won't even start. The harder case is when the YAML is valid but the logic is wrong — that's where log-level analysis like Daxtack's actually earns its keep, since there's no linter for "this job ran but did the wrong thing."

YAMLCI/CDGitHub ActionsGitLab CISyntax ErrorsDebuggingPipeline Configuration

Debug CI/CD failures in 30 seconds

Daxtack uses AI to automatically analyze your build logs, find the root cause, and suggest fixes — right in your pull request.

Related Articles