Skip to content
Quasar Tools Logo

yaml-cpp Duplicate Keys Behavior Explained

How yaml-cpp handles duplicate keys in YAML mappings, what the spec actually says, why silent data loss happens, and how to detect duplicates before they reach production.

DH
Tutorials & How-Tos12 min read2,700 words

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.

LastValue winsEarlier values silently lost
0Errors by defaultyaml-cpp gives no warning
Undef.Spec saysYAML 1.2 calls it undefined

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

Duplicate keys at different nesting levels are not duplicates — `database.host` and `cache.host` are entirely separate keys even though both use `host` as their local name. The duplicate-key rule applies only within a single mapping block, not across the entire document.

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.

YAML 1.2 specification, section 3.2.1.3

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

If your application deliberately writes YAML with duplicate keys expecting a specific resolution behavior, that code is relying on undefined behavior in the YAML specification. Any parser update could break it silently. Eliminate the duplicates and express the intent with explicit structure instead.

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.

Open tool

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 / LibraryLanguageDuplicate key behavior
yaml-cppC++Last value wins — silent, no warning
PyYAMLPythonLast value wins — silent, no warning
ruamel.yaml (strict)PythonRaises DuplicateKeyError when configured
js-yamlJavaScriptLast value wins — silent, no warning
gopkg.in/yaml.v3GoReturns error: duplicate map key
go-yaml v2GoLast value wins — silent, no warning
Psych (default)RubyRaises Psych::BadAlias / error in newer versions
SnakeYAMLJavaLast value wins — silent (configurable)
YamlDotNetC# / .NETLast value wins — silent, no warning
libfyamlCEmits 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

Use the [YAML Validator](/tools/data/validators/yaml-validator) to check your YAML files against the spec before committing them. For cross-language portability, treat any file that has duplicate keys as broken — even if your specific parser accepts it silently today.

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.

1

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.

2

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.

3

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.

4

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

The most dangerous duplicates are in security-critical keys: `admin`, `enabled`, `role`, `permissions`. Because yaml-cpp accepts duplicates silently, a config with `admin: false` followed by `admin: true` grants admin access while still displaying `false` to anyone who reads the file linearly. Run the [YAML Duplicate Key Detector](/tools/data/validators/yaml-duplicate-key-detector) on every security-related config file before deployment.

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.

Open tool

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

yaml-cpp supports merge keys when the `YAML::LoadAll` or `YAML::Load` function is used with YAML 1.1 documents. If you are using yaml-cpp with YAML 1.2 strict mode, merge keys may not be processed. Check your yaml-cpp version and document version declaration (`%YAML 1.2`) if merge keys appear to be ignored.

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 (`&lt;&lt;`) and anchors are not duplicates — they are intentional reuse mechanisms with defined priority rules.

Frequently Asked Questions

yaml-cpp uses last-value-wins semantics when parsing a YAML mapping with duplicate keys. If the same key appears more than once at the same mapping level, the parser overwrites the earlier value with the later one and emits no error or warning by default. The resulting in-memory Node object contains only the final value, with all previous values silently discarded. This matches the behavior of many other YAML parsers but is technically undefined by the YAML specification.

No — the YAML 1.2 specification states that duplicate keys in a mapping are "not allowed" and explicitly describes the behavior as undefined. However, the spec does not require parsers to throw an error; it only says the result is unspecified. Most parsers, including yaml-cpp, choose to silently accept duplicates rather than halt parsing, which makes duplicate keys a source of silent data-loss bugs rather than obvious runtime errors.

When yaml-cpp encounters a key it has already seen within the same mapping, it replaces the stored value with the new one. The earlier value is permanently lost — there is no way to retrieve it after parsing. This is called last-value-wins because whichever definition of the key appears last in the document is the one that survives. The rule applies at every nesting level independently.

Behavior varies across parsers. PyYAML (Python) also uses last-value-wins silently by default, though ruamel.yaml can be configured to raise an error. Go's gopkg.in/yaml.v3 raises an error on duplicate keys. JavaScript's js-yaml silently keeps the last value with no warning. Ruby's Psych raises an error. The inconsistency across parsers means a file that appears valid in one language's toolchain may silently lose data in another.

The fastest way is to paste your YAML into the Quasar Tools YAML Duplicate Key Detector, which scans the entire document including nested mappings and reports all duplicates with line numbers and both competing values. Alternatively, you can use a strict parser like gopkg.in/yaml.v3 in Go or ruamel.yaml in Python with the allow_duplicate_keys=False option. For CI/CD pipelines, yamllint with the rule braces: {forbid-flow-sequences: true} and key-duplicates: enable catches duplicates automatically on every commit.

Yes, in certain scenarios. If a YAML file is used for access-control configuration or feature flags, a duplicate key can silently override a security-critical value. For example, a key like `admin: false` followed later by `admin: true` would grant admin access due to last-value-wins, while the `false` entry looks like the effective value to anyone reading the file from top to bottom. This class of bug has appeared in real CVEs related to configuration file parsing. Automated duplicate detection is a low-cost safeguard.

A duplicate key is an unintentional or erroneous repetition of the same key name within a mapping. A YAML merge key (<<) is a standard YAML feature that deliberately incorporates the contents of an anchor into a mapping. The merge key itself is not a duplicate — it is a special key with defined semantics. However, if a merge key introduces a key that already exists in the target mapping, the explicitly defined key takes precedence over the merged value. This is intentional and not a duplicate-key bug.

In production code, yes. yaml-cpp's Node API does not natively expose a strict-mode option that errors on duplicates, but you can implement a post-parse validation pass using the YAML Duplicate Key Detector or a custom traversal that checks for repeated keys before your application reads the config. For critical configuration files — especially auth, security, and infrastructure configs — a duplicate-key check in your CI pipeline is strongly recommended. The Quasar Tools YAML Duplicate Key Detector is designed exactly for this use case.

ShareXLinkedIn

Related articles