MarkupSuite

YAML Syntax and Its Most Common Pitfalls

5 min readUpdated September 2026
A configuration file on a monitor

YAML is designed to read almost like plain notes: indentation for structure, dashes for lists, colons for key–value pairs. That friendliness is real, but it hides sharp edges that trip up newcomers and veterans alike. Knowing them turns most YAML debugging into a ten-second fix. Here is the core syntax, then the traps.

The core: maps, lists and scalars

A YAML document is built from three things. Mappings are key–value pairs written as key: value, and nesting one mapping under another simply means indenting it further. Sequences are lists, where each item begins with a dash and a space. Scalars are the leaf values: strings, numbers, booleans and null. Strings usually need no quotes, which keeps files clean, but you can quote them when a value would otherwise be ambiguous.

Two more rules cover most files. One file can hold several documents separated by a line of three dashes, which is why Kubernetes lets you put a Deployment and a Service in one manifest. Keys are unordered per the specification, so never rely on their order surviving a parser. And since YAML 1.2 is a superset of JSON, a pasted JSON snippet parses as-is.

Quoting styles and block scalars

YAML has three ways to write a string and they behave differently. Plain unquoted text is the default, and it is where type guessing happens. Single quotes make the text literal — no escape sequences at all, and an embedded quote is doubled. Double quotes are the only style that processes backslash escapes, so \n is a newline there and two plain characters everywhere else. Quote any value containing a colon followed by a space, or starting with #, &, *, %, or a dash, because those characters change what the line means.

For multi-line values, block scalars beat quoting. A pipe keeps newlines exactly as written, which is what you want for a shell script inside a GitHub Actions run: step. A greater-than sign folds the lines into one paragraph. Both accept a chomping indicator: a trailing dash strips the final newline, a plus keeps every trailing blank line, and the default keeps exactly one.

Pitfall one: tabs and indentation

The single most common YAML error is indentation. You must use spaces, never tab characters — a stray tab produces an immediate parse error. The number of spaces must also be consistent within a block, and a child must be indented strictly deeper than its parent. Because the eye cannot easily tell a tab from spaces, this is worth catching automatically: format the file and the structure either lines up cleanly or the parser points at the offending line.

Two habits prevent most of the pain. Set your editor to insert spaces for .yml and .yaml files — an .editorconfig with indent_style = space covers the whole team — then pick two spaces per level and never mix. Note too that a list item's dash counts as indentation, so items under a key may sit in the key's own column or deeper.

Pitfall two: the Norway problem

YAML guesses the type of unquoted scalars, and that guessing bites. The classic example is the country code NO, which older YAML versions read as the boolean false — the infamous "Norway problem." The words yes, no, on and off behave the same way, and a value like 1.20 loses its trailing zero because it is read as a number. The cure is simple: quote any string that could be mistaken for a boolean, a number or a date.

The same guessing hits other shapes. Under YAML 1.1 a leading zero means octal, so a postal code written 01234 comes back as 668, and colon-separated values like 12:30 are read as base-60 integers and become 750. YAML 1.2 narrowed the core schema, but many libraries — PyYAML among them — still default to 1.1 behaviour. Version numbers are a related trap: 1.10 is a number that displays as 1.1, while 1.10.1 is a string.

Pitfall three: anchors, aliases and duplicate keys

Anchors let you name a node with &defaults and reuse it later with *defaults, while the merge key << splices one mapping's contents into another. That is useful for repeated CI job definitions, but it means the file you read is not the structure the parser builds: someone searching for a key may never find it. Duplicate keys are the quieter version — most parsers keep the last one, so a setting edited near the top is silently overridden 200 lines down.

Aliases have a security angle too. A small file that references its own nested structures repeatedly can expand into gigabytes in memory — the YAML bomb, the same idea as XML's billion laughs. Permissive loaders in some languages also build arbitrary objects from tags, which is why Python's yaml.safe_load exists. Use anchors sparingly in config other people maintain.

Checking your work

The fastest check is to look at what the parser produced rather than at what you meant to write. Paste the YAML into the MarkupSuite YAML tab and convert it to JSON: quoted strings stay quoted, a guessed boolean shows up as bare true or false, aliases are expanded in place, and a duplicated key is simply not there twice. It runs in the browser, so a production manifest never leaves your machine.

The takeaway

Master maps, lists and scalars, use spaces not tabs, quote anything that could be mistaken for a boolean or number, and watch for aliases and duplicate keys. Convert YAML to JSON in MarkupSuite to verify how values were actually parsed.

Related tool
MarkupSuite · YAML

Open the tool and try it now