YAML for Developers: Common Indentation Errors and How to Debug Your Config

YAML is everywhere — Kubernetes manifests, GitHub Actions, Docker Compose, Ansible playbooks, Next.js config. It looks simple until a misplaced space silently breaks your deployment at 3 AM. This guide covers the errors developers hit most often and how to fix them.

Why YAML Indentation Is So Painful

YAML uses indentation to represent structure — like Python, but stricter. There are no closing brackets to catch misalignment, no linting built into most text editors by default, and error messages from YAML parsers range from cryptic to misleading.

The fundamental rules are simple, but the edge cases are many:

  • Only spaces are allowed — tabs cause an immediate parse error
  • The number of spaces per indentation level can vary, but must be consistent within a block
  • All keys at the same level must be indented by the same amount
  • Child elements must be indented more than their parent

The 5 Most Common YAML Errors

1. Tabs Mixed With Spaces

The most common source of YAML parse errors. Tabs are visually indistinguishable from spaces in most editors but cause an immediate found character '\t' that cannot start any token error.

# WRONG — tab before port:
server:
	port: 8080  # ← This tab will break everything

# CORRECT — spaces only
server:
  port: 8080

Fix: Set your editor to insert spaces on Tab for YAML files. In VS Code: Format On Save + the YAML extension. In .editorconfig:

[*.yml]
indent_style = space
indent_size = 2

2. Inconsistent Indentation Within a Block

All keys in a mapping must start at the same column. Mixing 2-space and 4-space indentation within the same block causes a bad indentation of a mapping entry error.

# WRONG
database:
  host: localhost
    port: 5432  # ← 4 spaces instead of 2

# CORRECT
database:
  host: localhost
  port: 5432

3. Missing Space After the Colon

In YAML, a colon must be followed by a space (or newline) to be treated as a key-value separator. Without the space, the entire key:value is treated as a string.

# WRONG — treated as a single string "host:localhost"
database:
  host:localhost

# CORRECT
database:
  host: localhost

4. Unquoted Special Values

YAML auto-infers types from unquoted scalars. This causes silent data corruption where the YAML is technically valid but the parsed value is wrong.

# YAML 1.1 type coercion surprises:
enabled: yes          # → boolean true (not string "yes")
country: NO           # → boolean false (Norway problem!)
version: 1.10         # → float 1.1 (trailing zero lost)
port: 08080           # → integer 4160 (octal in some parsers!)
date: 2024-01-15      # → Date object (not string)

# Safe versions (quoted):
enabled: "yes"
country: "NO"
version: "1.10"
port: "08080"
date: "2024-01-15"

5. Wrong Sequence Indentation

List items (sequences) use a dash (-) and must be indented consistently. A common mistake is forgetting that the dash is part of the indentation.

# WRONG — services not indented under app
app:
name: my-app
services:
- api
- web

# CORRECT
app:
  name: my-app
  services:
    - api
    - web

Reading YAML Error Messages

When a YAML parser fails, the error message contains three key pieces of information:

  • reason — the human-readable error type (e.g., bad indentation of a mapping entry)
  • line — the line number where the error was detected (1-indexed)
  • column — the column where the parser got confused

Important: the reported line is where the parser noticed the problem, not necessarily where the mistake is. An indentation error on line 5 might be caused by a missing space on line 3. Always look at the lines before the reported error too.

Multi-line Strings: | vs >

Two block scalar indicators handle multi-line strings:

# Literal block (|) — preserves newlines
script: |
  #!/bin/bash
  echo "Hello"
  echo "World"
# Result: "#!/bin/bash
echo "Hello"
echo "World"
"

# Folded block (>) — wraps to single line
description: >
  This is a long description
  that spans multiple lines
  for readability.
# Result: "This is a long description that spans multiple lines for readability.
"

Use | for shell scripts, code, and content where newlines matter. Use > for long prose strings where you want line wrapping in the YAML source but a single paragraph in the output.

Anchors and Aliases: DRY YAML

YAML has a built-in mechanism for reusing values: anchors (&name) and aliases (*name). This is especially useful in CI/CD configuration files.

# Define a reusable block
defaults: &defaults
  environment: production
  replicas: 3
  timeout: 30

# Reuse it with merge key <<
api-service:
  <<: *defaults
  port: 8080

worker-service:
  <<: *defaults
  port: 8081

Note: anchors and aliases are resolved during parsing. When you convert YAML to JSON, aliases are expanded — the deduplication is lost in the JSON output.

Quick Debugging Checklist

  1. Run your YAML through a validator (like the one below) to get the exact line/column
  2. Check for tabs — search-and-replace all tabs with spaces
  3. Verify indentation consistency — all keys at the same level should align
  4. Quote any value that looks like a boolean, number, date, or null (yes/no/true/false/null/~)
  5. If error points to line N, inspect lines N-3 to N as well
  6. Use a YAML-aware editor with syntax highlighting to make structure visible

Use the YAML Validator to paste your config and get instant error feedback with line/column context. For converting between YAML and JSON, use YAML to JSON.

Frequently Asked Questions

Can I use tabs for YAML indentation?

No. The YAML specification explicitly forbids tab characters for indentation. Only spaces are allowed. This is a hard rule with no exceptions — a tab character will cause a parse error. Configure your editor to insert spaces when you press Tab (most editors have a 'Tabs → Spaces' setting per language or project). The .editorconfig file is a portable way to enforce this across editors.

Why does YAML parse 'no' and 'yes' as booleans?

YAML 1.1 (still used by many parsers) defines yes, no, on, off, true, false as booleans — case-insensitive. The infamous 'Norway problem': the ISO country code 'NO' becomes boolean false in a YAML mapping. Fix: always quote these values when you intend them as strings: 'no', 'yes', 'on', 'off'. YAML 1.2 dropped the yes/no/on/off booleans, but library support varies — js-yaml's default is YAML 1.1.

How do I write a multi-line string in YAML?

Two block scalar styles: literal block (|) preserves newlines exactly — each line in the YAML becomes a line in the string. Folded block (>) converts single newlines to spaces, treating the block as a wrapped paragraph (double newlines become single newlines). Both styles strip leading indentation relative to the first content line. Example: description: | → 'This is line 1\nThis is line 2'. Use | for shell scripts or code, > for long prose descriptions.