YAML gotchas: implicit types, indentation and the Norway problem
Most YAML bugs do not produce an error. The file parses, but a value has a different type or sits under a different parent than you intended. These are the cases to watch for.
Why YAML errors are often silent
YAML decides the type of an unquoted value by matching it against patterns, and it decides structure from indentation. Both rules are convenient for people writing configuration by hand, but a small change can produce a different, still valid document. The safest way to review a YAML file is to convert it to JSON with the JSON ↔ YAML converter and check the explicit result.
1. The Norway problem
In YAML 1.1, the plain words yes, no, on, off, y and n were booleans. A list of country codes therefore turned Norway into false:
countries:
- GB
- NO
- SEYAML 1.2, published in 2009, reduced booleans to true and false, and this tool follows the 1.2 core schema. However, some widely used libraries and tools still default to YAML 1.1 behaviour. The robust fix is to quote any value that must be a string: - "NO". The same applies to settings such as enabled: on that a 1.1 parser would read as a boolean.
2. Version numbers and identifiers that look like numbers
An unquoted version: 1.10 is the floating-point number 1.1. A Python version 3.10 becomes 3.1, a well-known source of broken CI pipelines. Other examples:
zip: 01234loses its leading zero and becomes the number 1234.id: 1e3becomes the number 1000.phone: +441234567890becomes a number and can lose precision.commit: 12345678may be parsed as an integer, whilecommit: 1234abcdstays a string, so the type depends on the value.
Quote version numbers, postal codes, phone numbers and identifiers. A string that is always quoted is never misread.
3. Null in many forms
In YAML, ~, null, Null, NULL and an empty value all mean null. A key with nothing after the colon, such as password:, is null rather than an empty string. If an empty string is required, write password: "".
4. Indentation that changes the meaning
Consider this configuration:
database:
host: db.internal
port: 5432
timeout: 30If timeout is meant to belong to database but is not indented, it becomes a top-level key and the application uses a default database timeout. No error is reported. When reviewing changes, pay close attention to indentation in the diff, and use an editor that shows indentation guides. YAML also forbids tab characters for indentation; use spaces only.
5. Lists of objects
A dash starts a list item, and the keys of an object inside the item must line up:
users:
- name: ada
role: admin
- name: lin
role: viewerThe second item's role is not aligned with name, which either causes a parse error or attaches role to the wrong level, depending on the exact indentation. Converting to JSON shows immediately which object each key belongs to.
6. Duplicate keys
If a key appears twice in the same mapping, the YAML specification says the document is invalid, but some parsers quietly keep the last value. In a long file this can hide a setting that was added at the bottom and overrides one at the top. This converter rejects duplicate keys so you notice them.
7. Special characters in plain strings
A colon followed by a space, a leading #, &, *, !, |, >, % or @, and a leading or trailing space all have special meaning or are trimmed. For example, message: Note: restart required is an error, and color: #ff0000 is read as an empty value followed by a comment. Quote such strings: color: "#ff0000".
8. Multi-line strings
| keeps line breaks exactly, while > folds single line breaks into spaces. Both add a final newline by default; use |- or >- to remove it. Choosing the wrong indicator changes the content of scripts and certificates in subtle ways.
A safe YAML style
- Quote every string that could be mistaken for a number, boolean or null.
- Indent with two spaces and never use tabs.
- Keep anchors and aliases to a minimum in files that many people edit.
- Validate files in CI with the same parser your application uses.
- When in doubt, convert to JSON and inspect the result. See JSON vs YAML for when each format fits best.