YAML Merge Key Precedence: Unresolved Migration Issue
0 reputation · 29 Nov 2022, 09:27 UTC
0 reputation · 29 Nov 2022, 09:27 UTC
Plan a zero‑downtime migration for a small Java application that relies on YAML configuration. The migration intends to use the merge key (<<) to reduce duplication while preserving existing behaviour.
The YAML 1.2 specification leaves the order of precedence for nested merge keys ambiguous. SnakeYAML 1.32 follows the intended precedence, but earlier releases (e.g., 1.29) inverted it, and some custom tag processors ignore merge keys entirely. Because the application serialises configuration to JSON at runtime, any loss or change in merged values could silently alter behaviour.
You cannot guarantee consistent merge key precedence across different YAML parser versions or implementations because the merge key (<<) is a YAML 1.1 feature that was not formally adopted into the YAML 1.2 core specification. While many libraries maintain backward compatibility, behavior varies: some treat << as a literal string key, others invert precedence, and some ignore it entirely.
The discrepancy between SnakeYAML 1.29 and 1.32 typically stems from how the library handles the merge sequence. In standard YAML 1.1, local keys always override merged keys, and in a sequence of merges (<<: [*anchor1, *anchor2]), the first anchor takes precedence. Versions that invert this behavior are deviating from the 1.1 specification, creating a risk where a configuration change in the YAML file results in a different JSON output after a library upgrade.
To achieve a zero-downtime migration without silent configuration drift, shift the validation from the parser to the output.
parser_version key to alert operators which library version is required to interpret the merge keys correctly.<< operator is used for developer convenience only and that the runtime JSON representation is the authoritative configuration.To refine this recommendation: Are you using a custom Constructor or Representer in SnakeYAML to handle specific Java types, or are you using the default Yaml.load() method?
Use comments to ask for clarification. Post a solution as an answer.
32,775 reputation · 29 Nov 2022, 20:19 UTC
In practice, the only reliable way to guarantee that a merge key’s precedence behaves the same at runtime is to pin the YAML parser to a known 1.1‑compliant release. SnakeYAML 1.32 implements the intended rule: local keys override merged keys, and the first mapping in a merge sequence wins. Earlier 1.29 inverts this, and a pure 1.2‑only parser will often drop the merge key altogether.
Embed a lightweight test in your CI pipeline that:
SnakeYAML 1.32 and the current runtime version.If a difference surfaces, the test will fail before deployment, alerting you to a precedence shift.
base: &base
timeout: 30
retry: 3
child:
<<: *base
timeout: 45
With the correct precedence, the resulting child.timeout will be 45 regardless of parser version.