RFC 8259 says object names SHOULD be unique — so duplicates are legal but the behavior is unpredictable. See which value each parser keeps, how to reject duplicates in Python and JavaScript, and how to find them.
Are duplicate keys allowed in JSON?
Yes — but the result is unpredictable. RFC 8259 says object names should be unique, not must, so duplicates are not a syntax error. Every mainstream parser (JavaScript, Python, Go, Java, jq) silently keeps the last occurrence and discards the earlier ones — but because the spec leaves it undefined, you cannot rely on that.
A duplicate key occurs when two or more properties in the same JSON object share the same name:
{
"id": 1,
"name": "Ada",
"id": 2 // duplicate!
}
What RFC 8259 actually says
The specification uses RFC 2119 keywords very deliberately here. Section 4 states that the names within an object should be unique — a recommendation, not a requirement. It then spells out the consequence: when the names within an object are not unique, the behavior of software that receives that object is unpredictable.
Two words carry all the weight:
- SHOULD, not MUST — a document with duplicate names is still well-formed JSON. Validators that only check syntax will pass it.
- Unpredictable, not undefined-and-harmless — the spec is warning you that two conforming parsers may legitimately disagree about what your document means.
RFC 8259 also defines what it means for an object to be interoperable: one whose names are all unique, so that every implementation receiving it agrees on the name-value mappings. Duplicate names put you outside that guarantee.
What real parsers actually do
- JSON.parse (V8 / SpiderMonkey) — keeps the last value. Silent.
- Python json.loads — keeps the last value. Silent.
- Go encoding/json — keeps the last value. Silent.
- Java Jackson — configurable; by default keeps the last value.
- jq — keeps the last value. Silent.
None of them error by default, which means duplicate keys cause silent data loss — one value is quietly overwritten.
// JavaScript — last value wins, no warning
JSON.parse('{"id": 1, "id": 2}'); // { id: 2 }
# Python — same
json.loads('{"id": 1, "id": 2}') # {'id': 2}
# jq — same
echo '{"id": 1, "id": 2}' | jq . # { "id": 2 }
How to make your parser reject duplicates
Both major languages let you opt into strict behavior. This is worth doing whenever you ingest JSON you did not generate yourself.
Python — object_pairs_hook
Python's json module hands object_pairs_hook the raw list of key/value pairs before they collapse into a dict, so you can detect repeats:
import json
def no_duplicates(pairs):
seen = {}
for key, value in pairs:
if key in seen:
raise ValueError(f"Duplicate key: {key!r}")
seen[key] = value
return seen
json.loads('{"id": 1, "id": 2}', object_pairs_hook=no_duplicates)
# ValueError: Duplicate key: 'id'
JavaScript — a reviver can't do it, so check the source text
A JSON.parse reviver runs after duplicates have already collapsed, so it cannot see them. Use a streaming or lossless parser when it matters:
// The reviver is too late — it only ever sees the surviving value.
// Use a parser that preserves duplicates, e.g.:
// npm i lossless-json → parse with { parseNumber } and inspect pairs
// npm i json-source-map → gives you byte offsets for every key
// Or lint the raw text before parsing (see the linter below).
How other formats handle it
JSON is unusually permissive here. If duplicate keys are a real risk in your pipeline, the format itself may be the fix:
- TOML — duplicate keys are explicitly invalid. The spec forbids redefining a key, and parsers raise an error.
- YAML 1.2 — duplicate mapping keys are an error in the spec; most loaders (including PyYAML with a strict loader) reject or warn.
- Protocol Buffers / Avro — a schema defines each field once, so duplicates are impossible by construction.
- JSON — the outlier: syntactically legal, semantically unpredictable.
Why duplicates almost always mean a bug
If both copies of the key are intentional, the right structure is an array. If one is a mistake — a copy-paste error, a template substitution gone wrong, or a merge artifact — one value is dropped without warning. Neither case is what the author wanted.
How to find duplicate keys
The JSON FYI linter flags every duplicate key with the line and column of both the original definition and the duplicate. Paste your JSON securely into the linter.
Top comments (0)