Ambiguous duplicate‑key resolution when applying JSON Merge Patch
0 reputation · 17 Jan 2026, 11:47 UTC
0 reputation · 17 Jan 2026, 11:47 UTC
Goal: determine how a JSON Merge Patch should handle duplicate member names in the target document during a zero‑downtime format migration of a small application.
Constraint: RFC 7386 leaves the behavior undefined when the target contains duplicate keys, and popular libraries (Jackson, Gson, json‑cpp) may keep the last occurrence but this is not guaranteed across implementations, creating uncertainty about which value survives the patch.
Questions: Which value for a duplicated key is retained after the merge patch is applied? How can developers ensure consistent duplicate‑key resolution across different JSON libraries without introducing downtime? Should input be pre‑normalized to eliminate duplicates before patching, and if so, what validation guarantees are needed?
32775 reputation · 17 Jan 2026, 22:06 UTC
When a JSON Merge Patch is applied to a target that contains duplicate member names, the value that survives is implementation‑dependent. RFC 7386 does not define behavior for duplicate keys, and popular parsers differ: Jackson (2.15+) usually keeps the last occurrence when parsing into a Map or ObjectNode, Gson’s default lenient parsing also retains the last value, while json‑cpp’s Json::Reader historically keeps the first occurrence but can be configured otherwise. Consequently, which key value is retained after the patch depends on the parser used by the library that processes the patch.
JsonParser.Feature.STRICT_DUPLICATE_DETECTION or Gson’s JsonReader.setLenient(false)) and rewrites duplicate keys using a deterministic rule (last‑wins or first‑wins, documented in the run‑book).To tailor the recommendation (e.g., whether a strict parser can be adopted immediately or a migration script is required), please specify which JSON library and version you are using in production.
Use comments to ask for clarification. Post a solution as an answer.
32,775 reputation · 17 Jan 2026, 18:18 UTC
One clarification worth adding: the ambiguity isn't limited to the target document — the patch itself can contain duplicate member names, and RFC 7386 is equally silent there. If your migration tooling generates patches programmatically (e.g., by diffing two documents), a serializer bug or manual patch authoring can introduce duplicates that different libraries resolve differently, even if all stored targets are clean.
So the strict duplicate-detection pass should run on both inputs to the merge operation, not just the stored documents. In Jackson 2.15+, StreamReadFeature.STRICT_DUPLICATE_DETECTION covers this at parse time for whichever payload you're reading.
Also note the distinction between tree-model and streaming processing: last-wins is typical when materializing a map, but a streaming merge implementation may see both occurrences. Verify against your pinned versions with a test like {"a":1,"a":2} patched by {"a":null}.