How to use the YAML Validator and Linter
- Paste the YAML, open a file, or load one of the examples.
- Leave the file type on Auto-detect, or pick Kubernetes, Docker Compose, GitHub Actions or Ansible.
- Fix syntax errors first, at the line and column shown.
- Work down the findings; each one names the line and gives the text to write.
What a YAML validator checks
A YAML validator first parses the file against the YAML 1.2 specification and reports anything that stops a parser, such as a tab used for indentation or a missing colon, with its line and column. A useful validator then goes further, because a file that parses can still be wrong: a duplicate key that silently overwrites another, a no that one tool reads as false, or a Deployment whose selector does not match its pods.
This page does three passes: syntax, lint, and checks for the file type it detects.
The lint checks
| Finding | Why it matters |
|---|---|
| Duplicate key | YAML forbids it, but most parsers keep the last value and drop the first without a word |
| Tab in indentation | YAML allows only spaces; tools reject the file or read a different structure |
| Value read differently by YAML 1.1 | yes, no, on, off, 0755, 22:22 change type between parsers (the "Norway problem") |
| Key that YAML 1.1 reads as a boolean | on: becomes true: in PyYAML and other YAML 1.1 tools |
| Trailing whitespace | Invisible, noisy in diffs, and part of the value inside block scalars |
| Inconsistent indentation | Mixed 2- and 4-space levels make it easy to put a key at the wrong depth |
| Lines over 120 characters | Hard to review; information only |
No --- at the start | Optional; yamllint's default rule asks for it; information only |
The file-type checks
These are hand-written checks for the mistakes that come up most, not a full JSON Schema validation of each format, so a file can pass here and still be refused for a field this page does not know. The detected type is shown above the findings, and you can force a type.
- Kubernetes:
apiVersion,kindandmetadata.namepresent and valid; API versions removed from current clusters (extensions/v1beta1,batch/v1beta1CronJob and others); Deployment, StatefulSet and DaemonSetspec.selectormatching the template's labels; every container with a name and an image;containerPorta number, not a quoted string;envvalues strings; resource quantities such as256Miand500m(and the classicmemory: 512m, which is half a byte). - Docker Compose:
servicespresent, each withimageorbuild; unknown keys and typos such asenviroment; port mappings inhost:containerform and quoted, because22:22is the base-60 number 1342 to a YAML 1.1 parser; named volumes and networks declared;depends_onnaming real services, withservice_healthyonly for services that have a healthcheck; the obsolete top-levelversion. - GitHub Actions:
onandjobspresent; every job withruns-onandsteps; each step withusesorrunbut not both; actions pinned with@;needsnaming real jobs; and${{ github.event.issue.title }}or similar insiderun, which lets whoever opens an issue run shell commands. - Ansible: a playbook is a list of plays; each play has
hosts; unknown play keywords such ashandler(Ansible stops on them); tasks with no module or two modules (the error "conflicting action statements", usually a module's options not indented under it); the removedsudokeyword.
Worked example: a Compose file
services:
web:
build: .
ports:
- 22:22 # YAML 1.1 reads 1342
enviroment: # typo: Compose rejects the key
- NODE_ENV=productionThe validator reports the unquoted port, suggests - "22:22", and names environment as the key that was meant. To check the same on a server, docker compose config parses the file with Compose's own rules and prints the result, and kubectl apply --dry-run=server -f deploy.yaml asks the cluster to validate a manifest without applying it.
Fixing the most common errors
- "Tabs are not allowed as indentation": set your editor to insert spaces in YAML files.
- "Nested mappings are not allowed in compact mappings": a value contains
:. Quote it. - "Map keys must be unique": merge the two entries; only one survives otherwise.
- "Implicit keys need to be on a single line": look one line up for an unclosed quote.
With Shipown
Shipown deploys Dockerfile and Compose projects to your own Linux server and shows the ports, environment values and volumes before it runs. A Compose file that passes here, and docker compose config on the server, is one that will not fail the deploy on a typo. The Docker module docs cover the rest of the workflow.
Frequently asked questions
Is this a full Kubernetes or Compose schema validator?
No. The file-type checks are hand-written checks for the most common mistakes. For a complete check, run kubectl apply --dry-run=server or docker compose config as well.
Why is "on:" in my GitHub workflow flagged?
It is information only. GitHub reads it correctly, but YAML 1.1 parsers such as PyYAML turn the key into the boolean true, which confuses other tools that read the workflow.
What is the Norway problem?
In YAML 1.1 the unquoted values yes, no, on, off, y and n are booleans, so the country code NO becomes false. YAML 1.2 reads them as strings. Quoting the value makes every parser agree.
Why does memory: 512m fail in Kubernetes?
Lowercase m means milli, so 512m is 0.512 bytes. Write 512Mi for mebibytes or 512M for megabytes.
Which file type does auto-detect pick?
apiVersion and kind mean Kubernetes, jobs with on mean GitHub Actions, a services mapping means Compose, and a list of plays with hosts means an Ansible playbook. The page says which it used.
Is my YAML uploaded?
No. Parsing and every check run in your browser.