YAML validation errors are frustrating because the message is often technically correct but operationally unhelpful. The parser says did not find expected key, your CI says the workflow is invalid, and the actual mistake may be a colon, a tab, or one extra space on the previous line.
This guide is for developers editing Kubernetes manifests, Docker Compose files, OpenAPI specs, GitHub Actions workflows, Ansible playbooks, and application configuration. The goal is not just to make the red error disappear. The goal is to learn how to read YAML parser messages, choose the right validator, and avoid the subtle cases where valid YAML still breaks the tool that consumes it.
Quick answer
To fix a YAML validation error, inspect the reported line and the line above it, show hidden whitespace, quote strings containing : , align sibling keys, and run both a YAML parser and a schema-aware validator. A syntax validator proves the document can be parsed; it does not prove that Kubernetes, OpenAPI, or a CI platform accepts the resulting data.
Parser validation vs schema validation
The most useful distinction is syntax versus meaning. A YAML parser checks whether the text follows the YAML grammar and converts it into mappings, sequences, strings, numbers, booleans, and nulls. A schema validator checks whether that parsed data matches the rules of the consuming system.
| Check type | What it proves | What it cannot prove |
|---|---|---|
| YAML parser | The document is syntactically valid YAML. | Whether apiVersion, kind, paths, env, or jobs are legal for your platform. |
| YAML linter | The file follows style and risk rules such as indentation, duplicate keys, and truthy values. | Whether the application accepts the structure. |
| Schema validator | The parsed data matches a known contract such as Kubernetes, OpenAPI, or JSON Schema. | Whether the config works at runtime in your environment. |
| Application dry run | The target tool can process the config in context. | Whether every future version of that tool will behave the same way. |
In real incidents, I treat these as separate gates. First, make the file parse. Second, make the data shape match the platform. Third, run the platform's own dry run. Skipping directly to the final error message is how people spend an hour debugging a Kubernetes field name when the real problem is a colon in a string three lines earlier.
A reliable YAML error triage workflow
Use this order when a file fails in CI or during deploy. It keeps you from mixing parser errors, lint warnings, and application schema errors into one vague problem.
- Validate syntax first. Do not start with the application error from Kubernetes, Docker Compose, or GitHub Actions.
- Inspect the reported line and the line above it. YAML parsers often report where confusion becomes unavoidable.
- Turn on whitespace rendering. Tabs, non-breaking spaces, and pasted zero-width characters can look normal.
- Reduce the file to the smallest failing block. Delete unrelated sections until one mapping or sequence still fails.
- Run a parser and a linter. The parser catches grammar; the linter catches style and risky patterns.
- After syntax passes, validate against the target schema. YAML validity is not the same as Kubernetes or OpenAPI validity.
# 1. See hidden characters near the failing line
sed -n '1,80l' config.yaml
# 2. Parse with Python. This checks syntax, not platform schema.
python - <<'PY'
import sys, yaml
with open("config.yaml", "r", encoding="utf-8") as f:
data = yaml.safe_load(f)
print(type(data).__name__)
PY
# 3. Lint for risky patterns
yamllint config.yamlIf the file is small or you only have a snippet, paste it into the YAML Validator first. If it belongs to a repository, add a command-line check so the same mistake cannot come back in a later pull request.
Common YAML validation errors and what they really mean
Error text differs across parsers, but the failure patterns repeat. This table is the fastest starting point when you do not yet know whether the issue is indentation, a scalar value, an anchor, or a schema mismatch.
| Message fragment | Likely cause | First move |
|---|---|---|
| mapping values are not allowed here | A colon-space appeared inside an unquoted scalar, or a key is indented at the wrong level. | Quote suspicious strings, then inspect the previous line for an unfinished value. |
| did not find expected key | A sibling key is not aligned with the rest of the mapping, or a block scalar ended at the wrong indentation. | Compare column positions for the failing line and the two lines before it. |
| found character that cannot start any token | Most often a tab used for indentation, or an invisible copied character. | Show whitespace in the editor or run a command that prints hidden characters. |
| bad indentation of a mapping entry | A child key is indented less than its parent expects, often after a list item. | Normalize to two spaces and align all siblings in the same parent. |
| unknown anchor | An alias references an anchor that is defined later, misspelled, or in another YAML document. | Define the anchor before use and keep it before any document separator. |
| duplicated mapping key | The same key appears twice in one mapping. Some parsers warn; some overwrite silently. | Rename the key or merge the values explicitly instead of depending on parser behavior. |
Fix mapping values are not allowed here
This is the classic YAML message that looks more mysterious than it is. In plain English, the parser found a colon in a place where it was not ready to start a new key-value pair. The most common production version is a string value containing colon-space.
Invalid
metadata: message: Error: file not found url: http://localhost:3000
Valid
metadata: message: "Error: file not found" url: "http://localhost:3000"
Notice that http://localhost:3000 often parses fine because the colon is not followed by a space. The risky form is Error: file not found. I still quote URLs and messages because future edits often add spaces, hashes, or braces that turn a harmless scalar into a parser puzzle.
Expert habit
Quote strings that are not meant to become YAML syntax: messages, URLs, version numbers, file paths, cron expressions, country codes, and anything copied from logs. It is less clever, but it survives edits.
Fix did not find expected key
This error often means the parser is inside a mapping and expected another aligned key, but found a line that belongs to a different structure. The broken line is frequently not the first wrong line. Look at the previous sibling and the parent.
Invalid
services:
api:
image: example/api
ports:
- "8080:8080"Valid
services:
api:
image: example/api
ports:
- "8080:8080"YAML does not require two spaces specifically, but siblings must align at the same column. In teams, two spaces is a good convention because Kubernetes, Docker Compose, GitHub Actions, and most examples use it. For a focused indentation-only walkthrough, use the YAML indentation errors guide.
Runnable example: catch YAML syntax errors with js-yaml
Browser validators are useful, but it is better to reproduce the parser error in code. This Node.js script uses js-yaml to load a file and print the parser location when YAML fails.
# Install
pnpm add js-yaml
pnpm add -D @types/js-yaml tsx
# validate-yaml.ts
import fs from "node:fs";
import yaml from "js-yaml";
const file = process.argv[2];
if (!file) {
console.error("Usage: pnpm tsx validate-yaml.ts <file.yaml>");
process.exit(1);
}
try {
const source = fs.readFileSync(file, "utf8");
const parsed = yaml.load(source, { json: false });
console.log("YAML parsed successfully");
console.log(JSON.stringify(parsed, null, 2));
} catch (error) {
if (error instanceof yaml.YAMLException) {
console.error(error.message);
process.exit(1);
}
throw error;
}
# Run
pnpm tsx validate-yaml.ts config.yamlThe important option here is json: false. When set to true, duplicate keys are allowed in a JSON-like way and later values override earlier ones. For config files, I prefer duplicate keys to fail loudly because silent overwrites are rarely intentional.
Runnable example: parse safely with PyYAML
In Python, use safe_load for untrusted or ordinary config. Avoid the old habit of calling yaml.load without a safe loader; you do not need arbitrary Python object construction to read a config file.
# Install
python -m pip install PyYAML
# validate_yaml.py
import json
import sys
import yaml
path = sys.argv[1] if len(sys.argv) > 1 else None
if not path:
raise SystemExit("Usage: python validate_yaml.py <file.yaml>")
try:
with open(path, "r", encoding="utf-8") as fh:
data = yaml.safe_load(fh)
except yaml.YAMLError as exc:
print(exc)
raise SystemExit(1)
print("YAML parsed successfully")
print(json.dumps(data, indent=2, default=str))
# Run
python validate_yaml.py config.yamlOne practical difference between parser versions is scalar resolution. YAML 1.1 treated values like yes, no, on, and off as booleans. YAML 1.2 narrowed boolean handling, but not every ecosystem has the same defaults. Quote values that must remain strings.
Use yamllint for errors a parser may not protect you from
A parser answers "can this be read?" A linter answers "is this file likely to surprise the next tool or developer?" That second question matters for duplicate keys, indentation conventions, truthy values, line length, and document markers.
# Install
python -m pip install yamllint
# Run with the default rules
yamllint config.yaml
# Run with a small project config
cat > .yamllint <<'YAML'
extends: default
rules:
indentation:
spaces: 2
line-length: disable
truthy:
allowed-values: ["true", "false"]
YAML
yamllint config.yamlI disable line length for generated manifests and keep duplicate-key checks strict. Long lines are noisy. Duplicate keys are dangerous because a deployment can appear to use one value while the parser quietly keeps another.
When valid YAML is still wrong
This is the trap behind many "but the YAML validator says it is valid" bugs. Valid YAML only means the document parses. The following file is syntactically valid YAML:
apiVersion: apps/v1 kind: Deployment metadata: name: demo spec: replicas: "three"
A YAML parser accepts it because "three" is a valid string. Kubernetes rejects it because replicas must be an integer. OpenAPI has the same pattern: syntax can pass while a path object, schema object, or security scheme is invalid.
Kubernetes
Use kubectl --dry-run=server or kubeconform after syntax validation.
OpenAPI
Use a spec-aware linter such as Redocly CLI or Spectral, not only a YAML parser.
GitHub Actions
Use actionlint because workflow rules go beyond YAML syntax.
Version and parser differences that matter
YAML is not one perfectly uniform runtime behavior. The YAML 1.2.2 specification is the modern reference, but many tools are backed by libraries with their own defaults, compatibility choices, and historical behavior. The practical move is to validate with the same parser family your platform uses whenever the file is important.
Truthy strings
Quote no, yes, on, off, y, n, and country codes such as NO if the value must remain a string. YAML 1.1 compatibility still appears in real tooling.
Duplicate keys
Some parsers reject duplicate mapping keys; others keep the last value. In configuration, duplicates should be treated as an error even if a parser accepts them.
Anchors and merge keys
Anchors are YAML syntax, but merge-key behavior is not always supported uniformly in higher-level platforms. Avoid clever anchors in files maintained by many people.
Multiple documents
The --- separator creates separate documents. Anchors cannot be referenced across document boundaries, and some tools only read the first document.
When not to trust a simple YAML validator
A browser-based validator is excellent for quick syntax triage, especially when the CI error hides the real parser message. It is not enough for files that are governed by another specification.
Use a schema-aware tool when the YAML describes:
- Kubernetes manifests, CRDs, Helm templates, and admission-controlled resources.
- OpenAPI or AsyncAPI specifications where object names and schema keywords matter.
- GitHub Actions, GitLab CI, CircleCI, or other workflow files with platform-specific fields.
- Security-sensitive config where duplicate keys or type coercion could change behavior.
The practical rule: use the YAML Validator to answer "is this YAML?" Then use the platform tool to answer "is this the right YAML for this system?"
Production checklist before committing YAML
- The file parses with the same YAML library or platform parser used in production.
- Whitespace rendering is enabled and tabs are not present.
- Duplicate keys are rejected by linting or review.
- Strings that look like booleans, numbers, dates, cron expressions, URLs, or log messages are quoted.
- The target schema or platform dry run passes after syntax validation.
Frequently asked questions
What does mapping values are not allowed here mean in YAML?
It usually means the parser found a colon where it was not expecting a mapping separator. Common causes are an unquoted string containing colon-space, a key indented at the wrong level, or a previous line that accidentally started a scalar value.
Why does YAML validation pass but Kubernetes or OpenAPI still rejects the file?
A YAML parser only checks syntax and turns the document into data. Kubernetes, OpenAPI, GitHub Actions, and other platforms then apply their own schema rules. A file can be valid YAML but invalid for the target application.
Should I use an online YAML validator or a command line linter?
Use an online validator for quick syntax triage and small snippets. For project files, use the same parser or linter your application uses, such as yamllint, PyYAML, js-yaml, kubeconform, or an OpenAPI linter.
Can YAML validators catch duplicate keys?
Some validators and linters can catch duplicate keys, but not every parser rejects them by default. Treat duplicate keys as a bug because one value usually overwrites another and the behavior may differ across tools.
What is the fastest way to debug a YAML parser error?
Start at the reported line and also inspect the line above it. YAML errors often point to where the parser finally got confused, not the exact line that introduced the problem.
Try These Tools
YAML Validator
Paste YAML and find parser errors with line and column context.
Open toolYAML Formatter
Normalize indentation and make nested YAML easier to review.
Open toolYAML to JSON Converter
Convert parsed YAML into JSON to inspect the actual data structure.
Open toolYAML to JSON Schema
Generate a starting schema when syntax is valid but data shape needs enforcement.
Open toolAuthoritative references
For implementation details, use primary documentation alongside this guide:
- YAML 1.2.2 specification for the grammar and modern type-resolution model.
- js-yaml documentation for Node.js parser behavior and options.
- PyYAML documentation for Python loading functions and YAML exceptions.
- yamllint documentation for project lint rules that catch risky but parseable YAML.
Related tutorials
YAML Indentation Errors
Fix tabs, sibling alignment, nested lists, and block scalar indentation.
YAML Anchor and Alias Fix
Understand unknown anchors, merge keys, and parser compatibility.
JSON vs YAML
Choose the right format and avoid YAML-specific type surprises.
Docker Compose Guide
See practical YAML in a multi-container configuration context.
Written by Zhisan
Independent Developer - Last updated July 2026