I once shipped a deploy that pinned a service to version 1.1 when the config file plainly said 1.10. Not a typo. Not a bad find-and-replace. The YAML file, which I had read four times, said this:
image_tag: 1.10
And the parser handed my deploy script the number 1.1. Because 1.10 isn't a version string to YAML — it's a float literal, and floats don't keep trailing zeros. Ten becomes one-point-one. The file was 100% valid YAML. The linter was happy. CI was green. The wrong container went out.
That's the thing nobody tells you about YAML validation: "valid" is not the same as "correct." A syntax checker that only answers yes/no is answering the easy question. The hard question — the one that actually breaks deploys — is what did my YAML turn into? Because YAML is not a config format, it's a type-inference engine wearing a config format's clothes, and it makes decisions about your data that you never asked it to make.
The YAML Validator on toolz.dev answers both questions. It tells you whether the document parses, and then it shows you the parsed result as JSON — the actual data structure your tooling will receive. That second half is what would have saved me. "image_tag": 1.1 in the output pane is impossible to misread.
TL;DR: Paste your YAML into the YAML Validator and read the JSON output, not just the green checkmark. That's where type coercion shows itself:
1.10→1.1,0123→123, unquoted values silently becoming numbers, booleans, or null. It runs on js-yaml (YAML 1.2) entirely in your browser, so Kubernetes secrets and database credentials never leave your machine. Quote anything that must stay a string. If you need to compare the result against a JSON config, the JSON Formatter and JSON Diff pick up from there.
What Does a YAML Validator Actually Check?
Two different things, and it's worth separating them because they fail differently.
Syntax validation asks: can this text be parsed at all? Tabs where spaces belong, a missing space after a colon, a block scalar whose body isn't indented, an unclosed quote. These are loud failures. Your parser throws, your pipeline goes red, you fix it in two minutes. Annoying, not dangerous.
Semantic inspection asks: what did it parse into? This is where the quiet failures live. The document is valid. The pipeline is green. The value is simply not what you thought you wrote. Nobody finds out until production behaves strangely, and by then nobody's looking at the config file, because the config file is "fine."
Most online YAML checkers only do the first one. The toolz.dev validator does the first and then hands you the second — the parsed document, rendered as JSON, right next to your input. Get in the habit of reading that pane. It's the difference between "the file is well-formed" and "the file means what I meant."
Which YAML Errors Actually Break Builds?
Here's what genuinely shows up, ranked by how much of my life each has cost me. Every behaviour below I verified against js-yaml 4, which is the parser the toolz.dev validator runs and which implements the YAML 1.2 spec.
1. Tabs. Always tabs.
YAML forbids tab characters for indentation. Not "discourages" — forbids. The spec is explicit, and the error message is refreshingly direct:
tab characters must not be used in indentation
The reason this keeps happening is that tabs are invisible. Your editor shows you a nicely aligned file; the parser sees a control character. Fix it at the source: set your editor to insert spaces, and turn on "render whitespace" for YAML files. Two spaces per level, which is the convention every major YAML ecosystem has settled on.
2. Duplicate keys
database:
host: localhost
port: 5432
host: production-db.example.com
host appears twice. What happens? It depends entirely on your parser, which is a horrifying sentence to write about a config format.
js-yaml throws: duplicated mapping key. Good. That's the behaviour you want, and it's what the toolz.dev validator will show you. But PyYAML — which is what Ansible, and a lot of Python tooling, sits on — silently takes the last value and moves on. No warning. Your database host is now whatever the last duplicate said, which in a long file you merged badly might be three hundred lines away from where you're looking.
This is the single best argument for running configs through a strict validator even when your production tooling accepts them. A validator that's stricter than your runtime is a validator that finds bugs.
3. Type coercion — the one that got me
YAML infers types from unquoted scalars. It is very confident and it is often wrong about your intent:
| You wrote | You meant | YAML 1.2 gives you |
|---|---|---|
version: 1.10 |
the string "1.10" | the float 1.1 |
pin: 0123 |
the string "0123" | the integer 123 |
port: "8080" |
the number 8080 | the string "8080" |
enabled: true |
boolean | boolean true — correct |
value: |
empty string, maybe? | null |
value: ~ |
a tilde | null |
That 0123 row is the one I'd tattoo on people. Zip codes, PINs, account numbers, zero-padded IDs — every leading zero you wrote for a reason gets eaten. Quote them.
The rule that has never once let me down: if the value is an identifier, a version, a code, or anything you'd never do arithmetic on, put it in quotes. Ports and replica counts can stay bare. Everything that merely looks numeric should be "quoted".
4. The version-dependent booleans (a.k.a. the Norway problem)
This one is genuinely notorious, and the details matter more than the meme.
In YAML 1.1, the boolean type accepts yes, no, on, off, y, n, and their capitalisations, in addition to true and false. So country: NO — Norway's ISO country code — parses as boolean false. In YAML 1.2, which cleaned this up, only true and false are booleans; NO is just the string "NO".
Which means the same file means different things in different tools:
country: NO
feature_flag: on
- js-yaml 4 (YAML 1.2, and what this validator uses):
{"country": "NO", "feature_flag": "on"}— strings. - PyYAML (YAML 1.1):
{"country": False, "feature_flag": True}— booleans.
Same bytes. Different data. If your CI runs a Python linter over a config that a Node service consumes, you have two parsers disagreeing about your file and neither of them is wrong.
This is also the origin of GitHub Actions' weirdest quirk: the on: key that every workflow starts with is a boolean to a YAML 1.1 parser, so scripts that lint workflow files in Python find a key called True instead of on. Quoting ("on":) is legal and fixes it.
The defensive move is the same as before: quote it. country: "NO" means "NO" in every parser that has ever existed.
5. Block scalar indentation
description: |
This is not indented
The | (literal) and > (folded) block scalars need their content indented relative to the key. Un-indented content ends the block immediately and the parser starts reading your prose as YAML keys, which produces error messages that appear to have nothing to do with the actual mistake.
Worth knowing the chomping indicators while you're here: | keeps a single trailing newline, |- strips it, |+ keeps all of them. If you're embedding a private key or a script and something downstream complains about a trailing newline, this is your knob.
6. Unquoted special characters
A colon-space inside an unquoted value ends the value and starts a new key. This bites in error messages and URLs:
message: Error: file not found # parse error
regex: [a-z]+ # parsed as a LIST, not a string
time: "22:22" # quote it — in YAML 1.1 this was base-60!
[, {, #, &, *, !, |, >, %, @ at the start of a scalar all mean something. Quote first, ask questions later.
How Do I Validate YAML on Toolz.dev?
- Open the YAML Validator. No account, no upload.
- Paste your document. A Helm values file, a docker-compose, a workflow — whatever's misbehaving.
- Hit Validate. Errors come back with the exact line and column from the parser, plus the parser's own reason string (
bad indentation of a mapping entry,duplicated mapping key, and so on). - Read the JSON output pane. This is the step people skip and it's the one that matters. Scan it for the values you care about. Is
image_taga string or a number? Is that port quoted? Did an empty value becomenull? - Fix, re-validate. Errors can mask each other — the parser stops at the first one it can't recover from, so fixing one sometimes reveals two more. That's normal, not a sign things are getting worse.
One known limitation, stated plainly
The validator currently parses a single YAML document. If you paste a multi-document file — several Kubernetes manifests separated by --- in one file, which is an extremely common pattern — it will report:
expected a single document in the stream, but found more
That's the parser being correct, not the file being broken. The workaround today is to validate each document separately: paste everything above the ---, check it, then paste the next chunk. Multi-document support is on my list precisely because Kubernetes users hit this immediately, and I'd rather tell you about the gap than let you discover it mid-incident.
YAML vs JSON: When Should I Use Which?
YAML 1.2 is a strict superset of JSON — every valid JSON document is valid YAML, which is why the validator can hand you JSON output at all. But the formats have opposite personalities.
| YAML | JSON | |
|---|---|---|
| Structure defined by | Indentation (whitespace-significant) | Braces and brackets (explicit) |
| Comments | Yes (#) |
No |
| Type inference | Aggressive — infers numbers, booleans, null, dates | None — quotes mean string, always |
| Multi-document | Yes (--- separator) |
No |
| Reuse | Anchors (&), aliases (*), merge keys (<<) |
None |
| Failure mode | Silent misinterpretation | Loud parse error |
| Best at | Files humans write and edit | Data machines exchange |
The trade is real and it goes both ways. YAML's readability and comments are exactly why infrastructure config lives there — nobody wants to maintain a 400-line Kubernetes manifest in JSON with no comments. JSON's total lack of cleverness is exactly why APIs use it: "1.10" is "1.10" and there is nothing to discuss.
My rule: YAML for files people edit, JSON for data machines pass. And when a YAML file gets generated by a program rather than typed by a person, that's a smell — machine-generated config gets none of YAML's benefits and all of its risks.
If you're moving between the two, the JSON to YAML converter handles the transformation, and the JSON Formatter will tidy up the other side.
What Are Anchors and Aliases, and Should I Use Them?
YAML lets you define a block once and reuse it. Anchor with &, reference with *, merge into a map with <<:
defaults: &defaults
adapter: postgres
host: localhost
port: 5432
development:
<<: *defaults
database: myapp_dev
test:
<<: *defaults
database: myapp_test
Both development and test come out with the adapter, host, and port merged in. It's genuinely useful, and js-yaml handles it — I verified the merge resolves correctly.
Two warnings, though.
First, merge keys are a YAML 1.1 extension, not part of the YAML 1.2 core. Support is widespread but not universal, and — the one that catches people — GitHub Actions does not support them. Anchors in a workflow file will not do what you want. Check your consumer before you lean on this.
Second, anchors make a file harder to read for the next person, and in config the next person is usually you at 2 a.m. I use them for genuinely repeated blocks and never for cleverness.
While we're on the dangerous side of YAML: the format supports custom tags that some parsers use to construct arbitrary objects. Python's yaml.load() was famously exploitable this way, which is why yaml.safe_load() exists and why you should use it — always — on any YAML that came from outside your team. js-yaml's load() in v4 is safe by default (it won't construct arbitrary types), which is one fewer thing to worry about here.
How Do I Stop Writing Broken YAML in the First Place?
Prevention beats validation, and most of it is editor configuration:
- Two spaces, never tabs. Set it per-filetype so you can't forget.
- Turn on whitespace rendering for
.yml/.yaml. If you can see the tab, you won't commit the tab. - Install a YAML language server. Real-time schema validation against Kubernetes, GitHub Actions, and docker-compose schemas catches an entire class of error that syntax validation can't: valid YAML with a misspelled key.
- Quote by default when in doubt. The cost of an unnecessary quote is zero. The cost of a missing one is a deploy.
- Validate before you push, not after CI fails. Pasting into a browser tab takes eight seconds; a failed pipeline takes eight minutes.
- For Kubernetes, layer the checks. Syntax validation catches structure;
kubectl apply --dry-run=clientcatches schema. They find different bugs and you want both.
And the habit that actually changed things for me: when a config-driven deploy does something inexplicable, look at the parsed output before you look at anything else. Not the file. The parsed output. The file is a story about what you meant. The parsed output is what actually happened.
That's the same instinct that governs everything in my API debugging workflow — read the data, not the code — and it applies just as well to configs as it does to responses. If you want the wider tour of what else lives in that toolbox, the coding tools guide covers it.
Frequently Asked Questions
Why does my YAML validate but still break my deployment?
Because syntax validity and semantic correctness are different things. YAML infers types from unquoted values, so 1.10 becomes the float 1.1, 0123 becomes the integer 123, and an empty value becomes null — all in a perfectly valid document. Read the parsed JSON output, not just the pass/fail result, and quote any value that must stay a string.
Why does YAML turn my version number into a different number?
1.10 is a float literal to YAML, and floats do not preserve trailing zeros, so it resolves to 1.1. Any version, build number, or zero-padded identifier must be quoted: version: "1.10". This is one of the most expensive YAML mistakes because the file looks right and the parse succeeds.
What is the Norway problem in YAML?
In YAML 1.1, the values no, NO, off, and yes are booleans, so Norway's country code NO parses as false. YAML 1.2 fixed this — only true and false are booleans — but many tools (notably PyYAML, which Ansible uses) still implement 1.1. The same file can therefore mean different things in different tools. Quoting the value (country: "NO") makes it a string everywhere.
Can I use tabs for indentation in YAML?
No. The YAML specification forbids tab characters in indentation, and parsers reject them with an error like "tab characters must not be used in indentation." Configure your editor to insert spaces for YAML files — two spaces per level is the standard convention.
Does the Toolz.dev YAML Validator support multi-document files?
Not currently. It validates a single document, so a file containing several Kubernetes manifests separated by --- returns "expected a single document in the stream." Validate each document separately as a workaround. Multi-document support is planned.
Are duplicate keys allowed in YAML?
The specification says mapping keys must be unique, but parsers disagree in practice. js-yaml — which this validator uses — throws a "duplicated mapping key" error. PyYAML silently keeps the last value, which means a duplicate can quietly override your configuration with no warning at all. Running your config through a strict validator catches this before your runtime silently accepts it.
Is it safe to validate Kubernetes secrets and credentials online?
With the toolz.dev validator, yes — parsing happens entirely in your browser via JavaScript and nothing is transmitted to any server. You can confirm this yourself by opening your browser's Network tab while you validate and observing that no request is made. Apply that same check to any online tool before pasting infrastructure configuration into it.
What is the difference between .yml and .yaml?
Nothing functional — both extensions are recognised by every YAML parser. The official recommendation is .yaml; .yml survives from the era of three-character extensions and remains extremely common (Docker Compose and GitHub Actions both default to it). Pick one and stay consistent within a project.
How do I convert YAML to JSON?
Paste the YAML into the validator and read the output pane — it renders the parsed document as JSON, which is the conversion. Because YAML 1.2 is a superset of JSON, every valid YAML document has a JSON equivalent, but type inference is applied first, so an unquoted 1.10 arrives as 1.1 and 0123 as 123. Quote those values first if you need them preserved as strings.
How do I validate YAML against a schema?
This validator checks syntax and shows the parsed result, but it does not validate against a schema — that is a separate check confirming your keys and value types match what a tool like Kubernetes or GitHub Actions expects. For schema validation, use a YAML language server in your editor, or a schema-aware CLI such as kubeconform for Kubernetes or kubectl apply --dry-run=client. Syntax and schema validation catch different bugs, so run both.

