{}JSON FYI

Are duplicate keys valid in JSON? RFC 8259 behavior explained

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.

·8 min read

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 below:

Find the problem with the JSON linter →

The linter surfaces trailing commas, duplicate keys, and other common issues with line and column numbers.

Open JSON Linter →

How to fix them

  • Remove the duplicate if it was added by mistake — keep the intended key and delete the other.
  • Merge into an array if both values are valid: "roles": ["admin", "editor"]
  • Rename one key if both values belong in the object under different names.

Preventing duplicates in generated JSON

// JavaScript — object spread deduplicates automatically (last value wins)
const merged = { ...defaults, ...overrides };
JSON.stringify(merged);  // safe — each key appears once

// Python — dict merge also deduplicates
data = {**defaults, **overrides}
json.dumps(data)

Frequently asked questions

Are duplicate keys allowed in JSON?+

Yes, syntactically. RFC 8259 says object names SHOULD be unique — a recommendation, not a requirement — so a document with duplicate keys is still well-formed JSON and most validators will pass it.

Why does RFC 8259 say object names should be unique?+

Because uniqueness is what makes an object interoperable. RFC 8259 defines an interoperable object as one whose names are all unique, so that every implementation receiving it agrees on the name-value mappings. Without that guarantee, two conforming parsers can legitimately disagree about what the document means.

What does 'the behavior is unpredictable' mean in RFC 8259?+

It means the spec does not tell implementations what to do with repeated names, so each one is free to choose. In practice most keep the last value, some keep the first, and a few raise an error — all of them conforming. Your document no longer has one agreed meaning.

Which value does the parser keep — the first or the last?+

Almost every mainstream parser (JavaScript's JSON.parse, Python's json.loads, Go's encoding/json, Jackson, jq) silently keeps the last occurrence. It is implementation-defined, so don't rely on it.

Do duplicate keys keep the last value in Python?+

Yes. json.loads('{"id": 1, "id": 2}') returns {'id': 2} — the last value wins and nothing is reported. To reject duplicates instead, pass an object_pairs_hook that raises when it sees a repeated key.

How do I detect duplicate keys before parsing?+

Lint the raw text rather than the parsed object, because parsing already discarded the duplicates. The JSON FYI linter reports every duplicate with the line and column of both the original and the repeat.

Are duplicate keys invalid in TOML and YAML?+

Yes. TOML explicitly forbids redefining a key, and YAML 1.2 treats duplicate mapping keys as an error. JSON is the outlier that allows them syntactically.

How do duplicates end up in production JSON?+

Template systems that append keys without checking, code that merges two objects with overlapping keys, or hand-edited JSON where a key was accidentally copy-pasted. Generated JSON is the most common source.

Related tools & guides