DEVESSENTIALS

YAML 1.2 Tabs vs Spaces: Indentation Rules, Parse Errors & Fixes

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

Does YAML 1.2 Allow Tabs for Indentation?

No — tabs are explicitly forbidden in both YAML 1.1 and YAML 1.2. This is a hard rule with no exceptions. A single tab character in your indentation triggers an immediate parse error:

found character '\t' that cannot start any token

Why no tabs? Different editors render tabs as different widths (2, 4, or 8 spaces depending on settings). Since YAML uses indentation to define structure, tab width ambiguity would cause the same file to parse differently across editors. The spec bans tabs entirely to guarantee consistent parsing regardless of environment.

YAML 1.2 vs YAML 1.1: Both versions forbid tabs for indentation. YAML 1.2 (released 2009) is stricter than 1.1 in some areas — it removed the yes/no/on/off boolean coercions — but the tab prohibition is identical in both versions. If you're looking for whether YAML 1.2 allows tabs: it does not.

Configure your editor to insert spaces on Tab for YAML files via .editorconfig:

[*.yml]
indent_style = space
indent_size = 2

[*.yaml]
indent_style = space
indent_size = 2

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.

YAML Indentation: 2 Spaces or 4 Spaces?

The YAML specification does not mandate a specific number of spaces — 2, 4, or any consistent amount works. The only hard rules are:

  • Use the same number of spaces consistently within each block
  • Child elements must have more indentation than their parent
  • Tabs are never allowed — spaces only

In practice, 2 spaces is the de facto standard in most ecosystems: Kubernetes manifests, GitHub Actions, Docker Compose, and Ansible all use 2 spaces by convention. Most YAML linters default to 2. Use 2 unless your project enforces 4.

# 2 spaces — most common
server:
  host: localhost
  port: 8080
  database:
    url: postgres://localhost/mydb
    pool: 10

# 4 spaces — also valid, less common
server:
    host: localhost
    port: 8080
    database:
        url: postgres://localhost/mydb
        pool: 10

# WRONG — mixing 2 and 4 within the same block
server:
  host: localhost
    port: 8080  # ← parser error: inconsistent indentation

Set your editor to enforce 2-space YAML indentation globally via .editorconfig:

[*.{yml,yaml}]
indent_style = space
indent_size = 2

YAML Sequence (List) Indentation Explained

Sequences (lists) are the most common source of indentation confusion. The dash - that marks each list item is part of the indentation, not a separate character.

# Pattern 1 — dash at same level as parent key (compact, common in K8s)
services:
- api
- web
- worker

# Pattern 2 — dash indented 2 spaces from parent (more readable)
services:
  - api
  - web
  - worker

# Both are valid — but DON'T MIX within the same list:
services:
- api
  - web   # ← parse error: inconsistent dash position

# Nested list — each level adds indentation
app:
  name: my-app
  services:
    - name: api
      port: 8080
      env:
        - NODE_ENV=production
        - PORT=8080
    - name: worker
      port: 8081

The rule for nested objects inside a list: the keys of the object must be indented relative to the dash. The dash itself counts as 2 characters (dash + space), so the object keys start at the same column or further right:

# CORRECT — keys aligned after the dash+space
users:
  - name: Alice     # dash at col 2, name at col 4
    role: admin     # role also at col 4
  - name: Bob
    role: viewer

# WRONG — keys not aligned with the first key
users:
  - name: Alice
  role: admin       # ← 'bad indentation of a mapping entry'
                    #   role should be at col 4, not col 2

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.

Should I use 2 or 4 spaces for YAML indentation?

The YAML spec doesn't mandate a specific number — both 2 and 4 spaces are valid as long as you're consistent within each block. In practice, 2 spaces is the community standard: Kubernetes, GitHub Actions, Docker Compose, and Ansible all use 2 spaces. Most editors and linters default to 2. Use 2 spaces unless your team or project enforces 4. The only thing that matters is consistency — never mix 2 and 4 within the same file.

What are the YAML indentation rules?

Three core rules: (1) Only spaces are allowed — tabs are forbidden by the spec and cause an immediate parse error. (2) All keys in the same mapping (object) must be indented by the same amount. (3) Child elements must have more indentation than their parent. Beyond these, YAML is flexible: you can use 2 spaces, 4 spaces, or any consistent amount per level. The most common style is 2 spaces per level.

What does 'bad indentation of a sequence entry' mean in YAML?

This error means a list item (marked with '-') is not aligned at the same column as the other items in the same list, or it is indented incorrectly relative to its parent key. The most common cause: the '-' dash is at the wrong column — usually it should be indented 2 spaces from the parent key, and all dashes in the same list must be at the exact same column. Example: if 'services:' is at column 0, the list items should have their '-' at column 2. Always look at the lines before the reported error too — the indentation mistake is often one or two lines above where the parser complains.

How do I check YAML syntax online?

Paste your YAML into the YAML Validator at devessentials.dev/yaml-validator — it reports the exact line and column of every syntax error, including tab characters, bad indentation, and sequence misalignment. For local validation, run: python3 -c "import yaml,sys; yaml.safe_load(sys.stdin)" < file.yml or npx js-yaml file.yml. Most editors also support real-time YAML linting with the appropriate extension (YAML extension in VS Code).

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.