yaml-cpp silently accepts duplicate keys in YAML mappings and keeps only the last value — no error, no warning, no indication that earlier values were discarded. The YAML specification explicitly calls this behavior undefined, yet every major parser makes its own choice. This guide explains what yaml-cpp does, how other parsers differ, what real-world scenarios produce duplicates, and how to detect them before they cause silent data-loss bugs in production.
What are duplicate keys in YAML?
A duplicate key occurs when the same key string appears more than once at the same level within a single YAML mapping. In a language like JSON this is equally undefined but visually obvious. In YAML, where mappings span multiple lines and files can be hundreds of lines long, duplicate keys are easy to introduce accidentally and just as easy to miss during review.
What a duplicate looks like
The simplest form is a direct repetition: a key defined at the top of a mapping and redefined further down, sometimes with a different value. This happens most often through copy-paste errors, incomplete refactors, or merging configuration snippets from different sources. The key names are byte-for-byte identical — same case, same spacing — just appearing twice in the same mapping block.
- Copy-paste error: a key block is duplicated when adding a new section based on an existing one
- Incomplete rename: a key is renamed but the original is not deleted, leaving both in the file
- Config merging: two YAML fragments are concatenated and both happen to define the same top-level key
- Comment-out reversal: a commented-out key is uncommented without removing the active replacement below it
- Template expansion: a generator or templating engine emits the same key twice from different conditional branches
Note
What the YAML spec actually says
The YAML 1.2 specification addresses duplicate keys directly and unambiguously: they are not permitted in a valid YAML mapping. Section 3.2.1.3 states that mapping keys must be unique within a given mapping. Any document containing duplicate keys is technically non-conformant.
The content of a mapping node is an unordered set of key/value node pairs, with the restriction that each of the keys is unique.
Undefined does not mean invalid parse
The critical nuance is that while the spec calls duplicate keys non-conformant, it does not mandate that parsers reject them with a hard error. Instead, the spec describes the behavior as undefined — meaning each parser implementation is free to handle duplicates however it chooses. This is why yaml-cpp, PyYAML, js-yaml, and other parsers all accept duplicates without throwing, even though the resulting document is technically invalid YAML.
Why this matters in practice
"Undefined behavior" in a specification means your application is relying on an implementation detail that could change between library versions. yaml-cpp currently uses last-value-wins, but nothing in the spec guarantees that. A future version could change to first-value-wins, raise an exception, or return an error node — and any of those changes would be spec-compliant. Code that accidentally relies on duplicate-key resolution behavior is brittle by definition.
Warning
yaml-cpp behavior in detail
yaml-cpp is the most widely used C++ YAML parsing library and the default choice in many C++ applications and game engines. When yaml-cpp encounters a duplicate key in a mapping, it parses both occurrences but retains only the last one in the resulting Node tree. The earlier value is overwritten and permanently gone from the parsed structure.
The last-value-wins rule
In yaml-cpp's implementation, each key in a mapping is stored in an ordered list of key-value pairs. When a duplicate key is parsed, yaml-cpp searches the existing list for a matching key. If found, it replaces the stored value with the new one. The earlier value node is released. From the application's perspective, querying `node["key"]` returns the last-defined value as if only one definition ever existed.
No diagnostic output by default
yaml-cpp does not emit any warning, log message, or exception when it overwrites a duplicate key. The parse succeeds with a `YAML::Node` that looks completely normal. There is no flag you can check after parsing to discover that duplicates were silently resolved. The only way to detect them is to check the raw text before parsing — which is exactly what a dedicated duplicate-key detector does.
Behavior is consistent across mapping styles
yaml-cpp applies last-value-wins consistently regardless of whether the mapping uses block style (keys on separate lines) or flow style with braces. Nested mappings are handled independently — duplicates are only compared within the same mapping level, not across the entire document tree. A key that appears in two sibling mappings at different nesting depths is not considered a duplicate.
YAML Duplicate Key Detector
Paste your YAML document and instantly find all duplicate keys at every nesting level — reports line numbers and both competing values so you can fix them before they reach yaml-cpp.
How other parsers handle duplicates
Because the YAML spec leaves duplicate-key behavior undefined, each parser ecosystem has made its own decision. The variation across languages is significant enough that a YAML file that passes silently in one pipeline can fail hard in another. Understanding the landscape helps you write portable YAML.
| Parser / Library | Language | Duplicate key behavior |
|---|---|---|
| yaml-cpp | C++ | Last value wins — silent, no warning |
| PyYAML | Python | Last value wins — silent, no warning |
| ruamel.yaml (strict) | Python | Raises DuplicateKeyError when configured |
| js-yaml | JavaScript | Last value wins — silent, no warning |
| gopkg.in/yaml.v3 | Go | Returns error: duplicate map key |
| go-yaml v2 | Go | Last value wins — silent, no warning |
| Psych (default) | Ruby | Raises Psych::BadAlias / error in newer versions |
| SnakeYAML | Java | Last value wins — silent (configurable) |
| YamlDotNet | C# / .NET | Last value wins — silent, no warning |
| libfyaml | C | Emits warning; behavior configurable |
The practical takeaway is stark: Go's `yaml.v3` treats duplicates as hard errors while yaml-cpp, PyYAML, and js-yaml all silently accept them. A YAML config file that works in your C++ application with yaml-cpp may immediately fail when the same file is processed by a Go service or a strict Python linter in a CI pipeline.
Tip
Real-world scenarios that cause duplicates
Most duplicate keys are not intentional. They appear through predictable patterns in how developers write and maintain YAML configuration files. Knowing the common causes helps you catch them at the source.
Config file growth over time
Long-lived configuration files accumulate changes from many contributors. A key defined months ago near the top of the file is redefined by a new contributor who did not realise it already existed. This is especially common in Helm `values.yaml` files, Kubernetes ConfigMaps, and Ansible variable files, where hundreds of keys may be spread across a file too long to review in full.
Merging config fragments from different teams
When two independent teams or microservices contribute to a shared YAML config, the same top-level key may be defined by both. The final merged file contains both definitions, and whichever appears last silently wins. This is a common source of environment-specific override bugs where the wrong team's value takes effect in production.
Comment-out and replace pattern
A developer comments out `timeout: 30` and adds `timeout: 60` immediately below as a replacement. Later, someone removes the comment characters from the old line — perhaps in a global search-and-replace or a misconfigured editor formatter — and both values become active. The last one wins, but which is last depends on where each line fell in the file.
Template or code generation bugs
CI/CD pipelines and infrastructure-as-code tools often generate YAML programmatically. A bug in the template logic — a conditional branch that does not correctly exclude a key already emitted by another branch — can produce valid-looking YAML with silent duplicates. The generated file passes yaml-cpp parsing, and the wrong value is used in production with no error logged.
Warning
Detecting and preventing duplicates
Duplicate keys are straightforward to detect with the right tooling. The challenge is catching them before they reach a production parser, not after the silent data-loss has already occurred. The following workflow covers detection at every stage from authoring to deployment.
Step 1: pre-commit detection with the YAML Duplicate Key Detector
The YAML Duplicate Key Detector scans your entire YAML document — including nested mappings at every depth — and reports every duplicate key with its line numbers and both the overwritten and surviving values. Paste your file before committing to catch issues instantly. No upload, no signup, and the file never leaves your browser.
Step 2: editor-level linting with yamllint
For teams working with YAML files daily, `yamllint` with the `key-duplicates` rule set to `enable` catches duplicates on every save. VS Code users can install the YAML extension (Red Hat) which integrates yamllint automatically. Adding yamllint to your pre-commit hooks and CI pipeline means duplicates never reach a code review where they might be missed.
Step 3: strict-mode parsing in your test suite
Even if your production code uses yaml-cpp, you can add a test-time validation pass using a strict parser. Parse every YAML config file with Go's `yaml.v3` or Python's ruamel.yaml in strict mode as part of your test suite. These parsers error on duplicates, giving you a hard test failure instead of a silent runtime bug. After running your duplicate checks, use the YAML Anchors and Aliases Validator to also confirm that your anchor and alias usage is clean.
YAML Duplicate Key Detector
Find all duplicate keys in any YAML document instantly — every nesting level scanned, line numbers reported, both values shown side by side.
Prevention: structural best practices
- Sort keys alphabetically — alphabetical order makes duplicate detection trivial during code review
- Use YAML anchors for shared values — instead of duplicating a block, define an anchor once and reference it with an alias
- Enforce yamllint in CI — a failing pipeline is a much stronger signal than a code-review comment
- Review large config diffs holistically — check the full file view, not just the changed lines, when reviewing config changes
- Keep files short — split large config files into focused sub-files to reduce the surface area for duplicates
Merge keys, anchors, and related gotchas
YAML's merge key (`<<`) and anchor/alias system are the legitimate mechanisms for reusing values across a document. Understanding how they interact with duplicate-key detection prevents false positives in your tooling and helps you use them safely.
How merge keys work
The merge key `<<` instructs a YAML parser to incorporate the key-value pairs from an anchored mapping into the current mapping. It is not a duplicate key — `<<` is a reserved indicator in the YAML 1.1 spec and a widely-supported extension in 1.2. When a merge key imports a key that already exists in the target mapping, the explicit definition in the target takes priority over the merged value. This is intentional and predictable behavior, unlike accidental duplicate keys.
Anchors and duplicate detection
YAML anchors (`&name`) and aliases (`*name`) are not duplicates. An anchor defines a reusable node; an alias references it. Both can appear many times in a document without creating a duplicate-key violation. The YAML Anchors and Aliases Validator specifically checks that every alias resolves to a declared anchor and that there are no circular references — problems distinct from duplicate keys.
When merge keys produce apparent duplicates
A merge key can create what looks like a duplicate if the anchored base mapping and the target mapping both define the same key. This is not a bug — the spec defines explicit keys as taking priority over merged keys. However, some duplicate-key linters report this as an error. If you see false positives in yamllint for `<<`-based configurations, confirm you are using merge keys correctly before suppressing the warning. For complex Helm `values.yaml` files that heavily use anchors, comparing versions with the Diff Highlighter for JSON/YAML Configs makes key-level changes easy to spot in pull requests.
Note
Key takeaways
- yaml-cpp uses last-value-wins for duplicate keys — earlier values are silently overwritten with no error or warning.
- The YAML 1.2 specification explicitly says duplicate keys are not allowed and describes the behavior as undefined.
- Parser behavior varies widely: Go's yaml.v3 errors on duplicates, while PyYAML and js-yaml silently keep the last value like yaml-cpp.
- Security-critical keys like `admin` or `enabled` are the most dangerous targets — a duplicate can grant or revoke access invisibly.
- Use the YAML Duplicate Key Detector to scan any YAML file and find duplicates at every nesting level before deployment.
- Add `yamllint` with `key-duplicates: enable` to your CI pipeline for automatic prevention on every commit.
- YAML merge keys (`<<`) and anchors are not duplicates — they are intentional reuse mechanisms with defined priority rules.