These details explain the odd parse results and errors that remain once you know the basics.
A few corners of the spec that come up in practice:
- Keys needn't be strings.
1: onehas an integer key,true: xa boolean one (in YAML 1.1,on:becomesTrue, famously breaking GitHub Actions'on:key in PyYAML-based tools). JSON conversion then stringifies or fails. - Complex keys:
?introduces an explicit key, which can be a sequence or mapping. Python can't use a list as a dict key, so loaders may reject such documents. - Implicit keys (without
?) must fit on one line and are limited to 1024 characters. - Plain multi-line scalars are allowed: a plain value may continue on more-indented lines, and the line breaks fold into spaces. This hides mistakes such as a forgotten
-that turns two list items into one string. - Indentation of sequences in mappings:
key:followed by- itemat the same column is valid, because the-counts as indentation. But within one sequence all dashes must align. - Tabs are forbidden for indentation but allowed as separation inside lines and inside quoted strings.
- Byte order marks are allowed only at the start of the stream; encodings must be UTF-8, UTF-16 or UTF-32.
- Document markers in strings: a line starting with
---or...at column 0 inside a block scalar ends the document; indent it. - Duplicate keys are invalid by the spec even though many parsers accept them.
Example
1: one # integer key
on: push # YAML 1.1 parsers: key is the boolean True
? [lat, lon] # complex key: a sequence
: point
items:
- first
- second
third # not a new item: continues "second" -> 'second third'
message: |
a line
--- indented, so it is text, not a document marker
# PyYAML (YAML 1.1) loads the first two keys as 1 and True, and
# fails on the complex key: "found unhashable key"Remember
- Keys can be numbers, booleans or even collections
- Plain scalars can continue on indented lines, hiding missing dashes
- Lines starting with --- or ... at column 0 end a document, even in a block scalar
Watch out for
- Dropping the - on a list item so it silently becomes part of the previous item's string.