YAML Config Errors: Why Tabs, Indentation, and 'no' Break Your File (2026)
Your CI pipeline fails with "did not find expected key." Your Kubernetes deployment silently uses the wrong value. Your country code NO (Norway) becomes false. Your version 1.20 becomes 1.2.
YAML looks simple but is full of traps. Its "human-friendly" design hides surprising type coercion and whitespace rules that cause silent, hard-to-debug config errors.
This guide covers the exact YAML gotchas that break config files—tabs, indentation, type coercion, and multi-line strings—with the rules to avoid them.
Trap 1: Tabs Are Forbidden
The rule
YAML does not allow tabs for indentation. Ever. Only spaces.
server:
port: 8080 # ← TAB here = parse error
Error: found character that cannot start any token
Why it's insidious
Your editor may show tabs and spaces identically. You copy-paste from somewhere that used tabs. The file looks perfectly aligned but fails to parse.
The fix
- Configure your editor: "insert spaces instead of tabs"
- Set YAML files to 2-space indentation
- Enable "show whitespace" to catch stray tabs
- Use a YAML linter (
yamllint) in CI
Trap 2: Indentation Defines Structure
Indentation = nesting
Unlike JSON's braces, YAML uses indentation depth to define structure. Wrong indentation = wrong data (or a parse error).
# These mean completely different things:
# Version A: port is inside server
server:
port: 8080
# Version B: port is a sibling of server (top-level!)
server:
port: 8080
The silent bug
Sometimes wrong indentation doesn't error—it just produces the wrong structure:
database:
host: localhost
port: 5432
timeout: 30 # ← 3 spaces instead of 2
Depending on the parser, timeout may be misplaced or error. Consistency is everything.
Rules
- Pick one indent width (2 spaces is convention) and never mix
- List items align under their key:
fruits:
- apple
- banana
- Never use tabs (see Trap 1)
Trap 3: The Norway Problem (boolean coercion)
The classic bug
countries:
- GB
- NO
- FR
What YAML 1.1 parsers see:
["GB", false, "FR"]
NO (Norway) became the boolean false!
The full list of surprise booleans (YAML 1.1)
These unquoted values become booleans:
| Becomes true | Becomes false |
|---|---|
yes, Yes, YES |
no, No, NO |
true, True |
false, False |
on, On, ON |
off, Off, OFF |
y, Y |
n, N |
The fix: quote strings that look like booleans
countries:
- "GB"
- "NO" # ← quoted, stays a string
- "FR"
Note: YAML 1.2 (used by newer parsers) removed yes/no/on/off, but many tools still use 1.1 semantics. When in doubt, quote it.
Trap 4: Number Coercion
Leading zeros and version strings
version: 1.20 # → 1.2 (trailing zero lost — it's a float!)
zip: 01234 # → 668 (octal!) or 1234, depending on parser
build: 010 # → 8 (octal interpretation)
phone: 5551234 # → 5551234 (number, loses any formatting)
The fixes
version: "1.20" # quote to keep exact string
zip: "01234" # quote codes/IDs
build: "010" # quote to avoid octal
phone: "5551234" # quote — it's an identifier, not math
Rule: If a value is an identifier, code, or version (not something you'll do math on), quote it.
Trap 5: Special Characters Need Quoting
Characters that break unquoted values
time: 10:30 # ← colon: parsed as {10: 30} map, not a time!
price: $9.99 # usually fine, but risky
ratio: 3:2 # ← colon problem again
path: C:\Users # ← colon + backslash
greeting: hello: world # ← colon mid-value = error
The fix
time: "10:30"
ratio: "3:2"
path: "C:\\Users" # also escape backslash in double quotes
greeting: "hello: world"
Single vs double quotes
| Quote | Escapes? | Use for |
|---|---|---|
'single' |
No escaping (literal) | Strings with backslashes, no escapes needed |
"double" |
Yes (\n, \t, \) | Strings needing escape sequences |
literal: 'C:\Users\file' # backslashes stay literal
escaped: "line1\nline2" # \n becomes a newline
Trap 6: Multi-line Strings (| vs >)
The two block styles
# Literal block (|) — keeps newlines
description: |
Line one
Line two
# Result: "Line one\nLine two\n"
# Folded block (>) — folds newlines into spaces
summary: >
This is one
long line
# Result: "This is one long line\n"
Chomping indicators (controlling the trailing newline)
keep: |+ # keep all trailing newlines
clip: | # single trailing newline (default)
strip: |- # no trailing newline
Common bug
Using > (fold) when you need | (literal), turning a multi-line script or key into one mangled line. For shell scripts, SSH keys, or certificates in YAML, always use |.
Trap 7: Anchors and References (the hidden feature)
YAML can reference repeated content—useful but surprising if you don't know it:
defaults: &defaults # define anchor
timeout: 30
retries: 3
production:
<<: *defaults # merge the anchor
host: prod.example.com
staging:
<<: *defaults
host: staging.example.com
Both production and staging inherit timeout and retries. If you see &name and *name, that's what's happening.
Validation Checklist
Before deploying a YAML config:
☐ No tabs (spaces only)
☐ Consistent indentation (2 spaces, never mixed)
☐ Quote boolean-like strings ("NO", "yes", "off")
☐ Quote codes/versions ("01234", "1.20")
☐ Quote values with colons ("10:30")
☐ Right block style (| for literal, > for folded)
☐ Lint it (yamllint config.yaml)
☐ Validate against schema if available
Quick Debugging
"did not find expected key" → indentation error or tab
Value is false but should be text → the Norway/boolean problem, quote it
Version lost a digit → number coercion, quote it
"mapping values are not allowed here" → unquoted colon in a value
Multi-line value is one line → used > instead of |
FAQ
Q: Why does my YAML fail with "found character that cannot start any token"?
A: You have a tab character. YAML forbids tabs for indentation—replace all tabs with spaces.
Q: Why did NO become false?
A: The "Norway problem." YAML 1.1 treats no, yes, on, off as booleans. Quote the value: "NO".
Q: How do I keep 1.20 from becoming 1.2?
A: Unquoted, it's parsed as a float. Quote it: "1.20".
Q: When do I use | vs >?
A: | (literal) preserves newlines—use for scripts, keys, certificates. > (folded) joins lines with spaces—use for long prose.
Q: Should I just use JSON instead?
A: JSON has no comments and is stricter (which avoids these traps), but YAML is more readable for config. If YAML's traps bite you often, JSON or TOML are safer alternatives.
Conclusion
YAML's readability hides sharp edges. Avoid config disasters by remembering:
- Spaces only, never tabs
- Consistent indentation defines structure
- Quote boolean-like strings (the Norway problem)
- Quote codes and versions (number coercion)
- Quote values with colons
- Right multi-line style (
|vs>) - Lint before deploy
When in doubt, quote it. A quoted string is almost never wrong; an unquoted value can silently become the wrong type.