JuliusBrussee/caveman · error · ValueError
duplicate
Error message
duplicate
What it means
While parsing a JSON object, walk decodes each key with raw_decode and requires it to be a string and not already present in the result dict. Since Python's json module normally keeps last-duplicate silently, this parser intentionally rejects duplicate keys to preserve lossless span tracking.
Solutions
- Deduplicate keys in the JSON source so each object has unique key names
- Pre-validate the text with json.loads(object_pairs_hook=list) and check for repeated keys
- Fix the producer that emits duplicate keys (templating or merge bug)
- If last-wins semantics are desired, normalize via stdlib json.loads before passing to parse
Example fix
# before
text = '{"branch": "a", "branch": "b"}'
value = parse(text) # ValueError: duplicate
# after
text = '{"branch": "b"}' # keep only the intended key
value = parse(text) Defensive patterns
Strategy: validation
Validate before calling
import json
def has_no_duplicate_keys(text):
seen = []
def hook(pairs):
keys = [k for k, _ in pairs]
if len(keys) != len(set(keys)):
raise ValueError("duplicate keys")
return dict(pairs)
json.loads(text, object_pairs_hook=hook)
return True Try / catch
try:
value = parse(text)
except ValueError as e:
if str(e) == "duplicate":
raise ValueError("JSON object contains duplicate keys; deduplicate before parsing") from e Prevention
- Never build JSON by string concatenation/templating; use json.dumps
- Validate incoming JSON with object_pairs_hook to detect duplicates early
- Fix upstream producers that merge configs with repeated keys
- Remember stdlib json silently keeps the last duplicate — don't assume parity
When it happens
Trigger: Parsing a JSON object text that contains two identical keys (e.g. {"a":1,"a":2}) or a non-string key token, through parse().
Common situations: Hand-edited or concatenated JSON fragments producing duplicate keys; server responses built by naive string templating; migrating from stdlib json (which tolerates duplicates) to this strict wire parser.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
Related errors
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/46cb7b52982381b9.
Report an issue: GitHub.
Appendix: source
Thrown at packages/middleware/python/caveman_middleware/_google_wire.py:37
raise ValueError("bounded")
white()
start = index
if text[index] == '"':
value, index = decoder.raw_decode(text, index)
strings[path] = (start, index, value)
return value
if text[index] == "{":
index += 1
result = {}
white()
if text[index] == "}":
index += 1
return result
while True:
white()
key, index = decoder.raw_decode(text, index)
if type(key) is not str or key in result:
raise ValueError("duplicate")
white()
if text[index] != ":":
raise ValueError("colon")
index += 1
result[key] = walk((*path, key), depth + 1)
white()
end = text[index]
index += 1
if end == "}":
return result
if end != ",":
raise ValueError("comma")
if text[index] == "[":
index += 1
result = []
white()
if text[index] == "]":
index += 1View on GitHub (pinned to 3ee70a1026)