The Norway problem: a country list loses Norway
countries:
- se
- no
- dk
In YAML 1.1 the bare words no, yes, on, off, y and n are booleans. PyYAML implements 1.1, so that list is ["se", false, "dk"]. Go's yaml.v3 and the yaml npm package implement 1.2, where they are strings. Quoting is the fix, and quoting is exactly how YAML says "this is a string".
yaml.version_divergence · run this example
Every GitHub Actions workflow has a key that is not "on"
on: push
jobs:
build:
runs-on: ubuntu-latest
Under YAML 1.1 the key `on` resolves to the boolean true, so the mapping has a key `true` and no key `on`. GitHub's own parser handles it, but a script reading the workflow with PyYAML and looking for "on" finds nothing. A divergent key is worse than a divergent value: the field is simply not there.
yaml.ambiguous_key · run this example
A file mode is the wrong number, and both readings are numbers
mode: 0755
YAML 1.1 reads a leading zero as octal, giving 493. YAML 1.2 reads it as decimal, giving 755. Both are integers, so nothing about the value looks wrong — the permissions are just not what was written. Quote it, or use 0o755, which only 1.2 understands.
yaml.version_divergence · run this example
YAML 1.1 has base-60 integers
timeout: 1:30
Under YAML 1.1 that is the sexagesimal integer 90. It was intended for durations and is a reliable surprise: a value that looks like a time becomes a number nobody wrote. Under 1.2 it is the string "1:30".
yaml.version_divergence · run this example
Tabs are forbidden as indentation and look identical to spaces
parent:
child: 1
YAML forbids tabs for indentation outright. Because a tab and four spaces are indistinguishable on screen, the error message points at a line that looks perfectly aligned. Configure your editor to insert spaces for .yaml and .yml.
yaml.tab_indentation · run this example
A non-breaking space is content, not indentation
parent:
child: 1
Copying YAML out of a rendered web page or a PDF frequently brings U+00A0 with it. YAML treats it as part of the value, so the line is structurally somewhere other than where it appears. Completely invisible in every editor.
yaml.invisible_whitespace · run this example
Duplicate keys, again, with a different set of behaviours
port: 8080
host: a
port: 9090
YAML requires unique mapping keys, but loaders disagree about enforcement: PyYAML keeps the last silently, others error. In a Kubernetes manifest or a CI config assembled from templates, this is how two sources of truth both appear to win.
yaml.duplicate_key · run this example