Fix: YAML 'mapping values are not allowed here' and Other YAML Syntax Errors
The Error
You edit a YAML file and get one of these errors:
yaml: line 5: mapping values are not allowed hereyaml: line 8: could not find expected ':'yaml: line 12: did not find expected keyError: yaml: line 3: found character that cannot start any tokenyaml: line 7: did not find expected '-' indicatorYou might see these from Docker Compose, Kubernetes (kubectl apply), GitHub Actions, Ansible, CI/CD pipelines, or any tool that parses YAML. The wording varies slightly between parsers, but they all mean the same thing: your YAML has a syntax error.
Why This Happens
YAML is whitespace-sensitive. Unlike JSON, where braces and brackets define structure, YAML uses indentation. This makes it readable but extremely easy to break. A single wrong space, tab character, or missing quote can make the entire file invalid.
The most common causes:
- Tabs instead of spaces. YAML forbids tabs for indentation. Period.
- Inconsistent indentation levels. Mixing 2-space and 4-space indentation within the same block.
- Unquoted special characters. Colons,
#,@,*,{,},[,], and other characters have special meaning in YAML. - Colons inside values without quoting. A colon followed by a space (
:) is a key-value separator. If your value contains one, you need quotes. - Wrong multiline string syntax. Missing or incorrect use of
|and>block scalars. - Trailing spaces after a key or at the end of a line.
- BOM (Byte Order Mark) characters. Invisible characters at the start of the file, often added by Windows editors.
Fix 1: Replace Tabs With Spaces
This is the number one cause of YAML errors. YAML does not allow tabs for indentation. Not sometimes. Not with a config flag. Never.
The error often looks like:
found character '\t' that cannot start any tokenBut tab-related issues can also trigger mapping values are not allowed here if the tab-based alignment lands in the wrong spot.
Check for tabs:
grep -P '\t' your-file.yamlOr with cat:
cat -A your-file.yamlTabs show up as ^I. Spaces show up as regular whitespace.
Replace all tabs with spaces:
sed -i 's/\t/ /g' your-file.yamlConfigure your editor to use spaces for YAML files. Every major editor supports this:
- VS Code: Add to your settings (
settings.json):"[yaml]": { "editor.insertSpaces": true, "editor.tabSize": 2 } - Vim: Add to
.vimrc:autocmd FileType yaml setlocal ts=2 sts=2 sw=2 expandtab - JetBrains IDEs (IntelliJ, PyCharm, etc.): Go to Settings > Editor > Code Style > YAML and set Use tab character to unchecked, Tab size and Indent to 2.
Fix 2: Fix Indentation Alignment
Every item in a YAML block must be at the same indentation level. Child items must be indented exactly one level deeper than their parent. “One level” is typically 2 spaces, but the only hard rule is consistency.
Broken — mixed indentation:
server:
port: 8080
host: localhost # ❌ 4 spaces, but "port" uses 2This triggers mapping values are not allowed here because YAML sees host as a continuation of the port value, not as a sibling key.
Fixed:
server:
port: 8080
host: localhost # ✅ same level as "port"Broken — list items at wrong level:
services:
web:
ports:
- "8080:80"
- "443:443" # ❌ extra indentationFixed:
services:
web:
ports:
- "8080:80"
- "443:443" # ✅ same levelRule of thumb: If you get mapping values are not allowed here, look at the line the error points to and the line above it. One of them is at the wrong indentation level.
Fix 3: Quote Values That Contain Colons
A colon followed by a space (:) is how YAML separates keys from values. If your value contains this pattern, YAML thinks it’s a nested key.
Broken:
message: Error: something went wrongYAML parses this as key message with value Error, then tries to parse something went wrong as another mapping. That gives you mapping values are not allowed here.
Fixed:
message: "Error: something went wrong"This applies to any value containing ::
# ❌ Broken
url: http://localhost:8080
time: 10:30:00
description: Note: this is important
# ✅ Fixed
url: "http://localhost:8080"
time: "10:30:00"
description: "Note: this is important"Note: A colon at the end of a value without a trailing space is technically valid YAML (key: value:), but quoting it anyway is safer and clearer.
Fix 4: Quote Special Characters
Several characters have special meaning in YAML. When they appear in values, they need quoting.
# ❌ Broken -- these all cause parse errors
password: p@ss#word!
regex: [a-z]+
command: echo {hello}
reference: *default
value: %SECRET%
flag: yes # Parsed as boolean true, not the string "yes"
version: 3.10 # Parsed as float 3.1, not string "3.10"
# ✅ Fixed -- quote them
password: "p@ss#word!"
regex: "[a-z]+"
command: "echo {hello}"
reference: "*default"
value: "%SECRET%"
flag: "yes"
version: "3.10"Characters that require quoting when they appear at the start of a value: *, &, !, %, @, `, {, }, [, ], |, >, ', ", #, ,, ?.
Characters that require quoting anywhere in a value: : (colon-space), # (space-hash).
Boolean gotcha: YAML 1.1 (used by many parsers) treats yes, no, on, off, true, false (and various capitalizations) as booleans. This is a notorious source of bugs:
# These are all booleans, not strings
country: NO # false, not Norway
answer: yes # true, not the string "yes"
enabled: on # true
# Quote them to keep them as strings
country: "NO"
answer: "yes"
enabled: "on"Fix 5: Fix Multiline Strings
YAML has two block scalar styles for multiline strings. Getting the syntax wrong triggers parse errors.
Literal block (|) — preserves newlines exactly:
script: |
echo "line 1"
echo "line 2"
echo "line 3"Folded block (>) — joins lines with spaces (like a paragraph):
description: >
This is a long description
that gets folded into a single
line with spaces.Common mistakes:
# ❌ Content must be indented under the block indicator
script: |
echo "not indented"
# ✅ Fixed
script: |
echo "indented"
# ❌ No content on the same line as the indicator
script: | echo "hello"
# ✅ Fixed
script: |
echo "hello"
# ❌ Inconsistent indentation within the block
script: |
echo "line 1"
echo "line 2" # extra indent becomes part of the string, which might not be what you want
# ✅ Fixed
script: |
echo "line 1"
echo "line 2"Block chomping indicators control trailing newlines:
# | -- keeps final newline (default)
# |- -- strips final newline
# |+ -- keeps all trailing newlines
command: |-
echo "no trailing newline"This matters in GitHub Actions and shell scripts where a trailing newline can change behavior.
Fix 6: Docker Compose YAML Errors
Docker Compose files are one of the most common places for YAML errors. Here are the most frequent mistakes:
Broken — wrong indentation under services:
services:
web: # ❌ should be indented
image: nginxFixed:
services:
web: # ✅ indented under services
image: nginxBroken — environment variables with unquoted colons:
services:
app:
environment:
- DATABASE_URL=postgres://user:pass@db:5432/mydb # ❌ colons in value**Fixed — use the mapping syntax or quote:
services:
app:
environment:
DATABASE_URL: "postgres://user:pass@db:5432/mydb"If Docker Compose can’t connect to your database even with correct YAML, see Fix: PostgreSQL connection refused or Fix: MySQL access denied.
Broken — ports as numbers without quotes:
services:
web:
ports:
- 80:80 # Works, but can cause issues in some parsers
- 8080:8080Docker Compose handles unquoted ports, but it’s best practice to quote them:
services:
web:
ports:
- "80:80"
- "8080:8080"Validate your Compose file:
docker compose configThis parses the file and outputs the resolved configuration. If there’s a YAML error, it tells you the exact line.
Related: Fix: Docker COPY Failed: File Not Found in Build Context
Fix 7: Kubernetes Manifest YAML Errors
Kubernetes manifests are deeply nested YAML, making indentation mistakes easy.
Broken — wrong indentation in Pod spec:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers: # ❌ should be indented under spec
- name: app
image: nginxFixed:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers: # ✅ indented under spec
- name: app
image: nginxBroken — list items not aligned:
spec:
containers:
- name: app
image: nginx
ports:
- containerPort: 80
env:
- name: DB_HOST # ❌ not aligned with the key above
value: localhostFixed:
spec:
containers:
- name: app
image: nginx
ports:
- containerPort: 80
env:
- name: DB_HOST # ✅ indented under env
value: localhostValidate before applying:
kubectl apply --dry-run=client -f manifest.yamlOr use a linter:
kubeval manifest.yamlRelated: Fix: The Connection to the Server localhost:8080 Was Refused (kubectl)
Fix 8: GitHub Actions Workflow YAML Errors
GitHub Actions workflows have a specific YAML structure. A syntax error causes the workflow to fail with:
.github/workflows/ci.yml: Invalid workflow fileBroken — wrong indentation under steps:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm install
name: Install # ❌ name should be part of the stepFixed:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install
run: npm installBroken — multiline run without block scalar:
steps:
- name: Build
run: npm install
npm run build # ❌ YAML sees this as a continuation, not a second commandFixed:
steps:
- name: Build
run: |
npm install
npm run buildBroken — expression with unquoted braces:
steps:
- name: Deploy
if: github.ref == 'refs/heads/main'
env:
TOKEN: ${{ secrets.DEPLOY_TOKEN }} # ✅ this is fine -- GitHub Actions handles it
MESSAGE: {deploy started} # ❌ bare braces are a YAML flow mappingFixed:
MESSAGE: "{deploy started}"Validate GitHub Actions workflows locally with actionlint:
actionlint .github/workflows/ci.ymlFix 9: Use a YAML Linter
Don’t eyeball YAML errors. Use a linter.
yamllint (the gold standard for YAML linting):
pip install yamllint
yamllint your-file.yamlExample output:
your-file.yaml
3:1 error wrong indentation: expected 2 but found 4 (indentation)
5:12 error too many spaces after colon (colons)
8:1 error trailing spaces (trailing-spaces)Configure yamllint with a .yamllint.yml file:
extends: default
rules:
line-length:
max: 200
indentation:
spaces: 2
truthy:
check-keys: falseVS Code extensions:
- YAML (by Red Hat) — validates YAML with schema support for Kubernetes, Docker Compose, GitHub Actions, and more. Install the
redhat.vscode-yamlextension. - yamllint — integrates yamllint directly into VS Code.
Online validators: If you can’t install tools, paste your YAML into yamllint.com for a quick check. Don’t paste secrets or credentials into online validators.
Fix 10: YAML Anchors and Aliases
YAML anchors (&) and aliases (*) let you reuse blocks of configuration. Incorrect syntax here triggers did not find expected key or could not find expected ':'.
Broken — alias used before anchor is defined:
services:
web:
<<: *common # ❌ alias used before it's defined
defaults: &common
restart: alwaysFixed — define the anchor first:
x-common: &common
restart: always
services:
web:
<<: *common # ✅ anchor is defined aboveBroken — wrong merge syntax:
defaults: &defaults
adapter: postgres
host: localhost
production:
<<: *defaults
host: prod-db # ✅ this correctly overrides host from defaults
<<: *other # ❌ duplicate merge keyYou cannot use << twice at the same level. Merge multiple anchors with a list:
production:
<<: [*defaults, *other]
host: prod-dbNote: Not all YAML parsers support anchors and aliases. GitHub Actions, for instance, supports them in some contexts but not others.
Still Not Working?
Remove BOM characters
If your file was created or edited on Windows, it might have a BOM (Byte Order Mark) at the very start. This invisible character causes errors like:
found character that cannot start any tokenCheck for BOM:
hexdump -C your-file.yaml | head -1If the first bytes are ef bb bf, you have a UTF-8 BOM. Remove it:
sed -i '1s/^\xEF\xBB\xBF//' your-file.yamlOr in VS Code: open the file, click the encoding indicator in the bottom-right bar (it might say “UTF-8 with BOM”), and select Save with Encoding > UTF-8 (without BOM).
Remove trailing whitespace
Trailing spaces are invisible but can cause issues, especially after a colon at the end of a line that should introduce a nested block:
server:·····
port: 8080Those trailing spaces after server: can confuse some parsers. Remove all trailing whitespace:
sed -i 's/[[:space:]]*$//' your-file.yamlCheck .yml vs .yaml
Both .yml and .yaml are valid extensions. The YAML specification prefers .yaml, but .yml is widely used. The issue arises when a tool expects a specific filename.
- Docker Compose: looks for
docker-compose.ymlorcompose.yml(since Compose V2) by default. Notdocker-compose.yaml. - GitHub Actions: requires files in
.github/workflows/with.ymlor.yamlextensions. Both work. - Kubernetes: accepts both extensions. No preference.
If your tool isn’t picking up your file, check the expected filename and extension in its documentation.
Multi-document YAML issues
YAML supports multiple documents in a single file, separated by ---. A misplaced separator causes parse errors:
apiVersion: v1
kind: Service
metadata:
name: my-service
--- # ✅ document separator
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-appMake sure --- is on its own line with no leading spaces and no trailing content.
Invisible characters from copy-pasting
Copying YAML from websites, PDFs, or Slack often introduces non-breaking spaces (U+00A0), smart quotes, or other invisible characters that look like normal whitespace but aren’t.
Check for non-ASCII characters:
grep -P '[^\x00-\x7F]' your-file.yamlIf you find them, retype the affected lines manually rather than trying to fix individual characters. This is especially common when copying from documentation sites that use typographic quotes (" ") instead of straight quotes (").
Validate against a schema
For tool-specific YAML, validate against the correct schema:
# Docker Compose
docker compose config
# Kubernetes
kubectl apply --dry-run=client -f manifest.yaml
# GitHub Actions
actionlint .github/workflows/*.yml
# Generic YAML
yamllint -d relaxed your-file.yamlSchema validation catches issues beyond syntax — like misspelled keys, wrong value types, or missing required fields — that a generic YAML parser won’t flag.
Related: Fix: IndentationError: unexpected indent (Python) — similar whitespace-sensitivity issues in Python.
Related Articles
Fix: Kubernetes Pod CrashLoopBackOff (Back-off restarting failed container)
How to fix the Kubernetes CrashLoopBackOff error when a pod repeatedly crashes and Kubernetes keeps restarting it with increasing back-off delays.
Fix: Error: Process completed with exit code 1 (GitHub Actions)
How to fix 'Process completed with exit code 1' and other GitHub Actions workflow failures. Covers reading logs, exit codes, Node.js/Python/Docker step failures, secrets and environment variables, GITHUB_TOKEN permissions, checkout issues, caching, timeouts, self-hosted runners, matrix strategy, and artifacts.
Fix: Docker Container Exited (137) OOMKilled / Killed Signal 9
How to fix Docker container 'Exited (137)', OOMKilled, and 'Killed' signal 9 errors caused by out-of-memory conditions in Docker, Docker Compose, and Kubernetes.
Fix: The Connection to the Server localhost:8080 Was Refused (kubectl)
How to fix 'the connection to the server localhost:8080 was refused' and other kubectl connection errors when the Kubernetes API server is unreachable.