{"id":"0074a00fffa7edc8","repo":"google/gson","slug":"duplicate-key-key","errorCode":null,"errorMessage":"duplicate key: {key}","messagePattern":"duplicate key: (.+?)","errorType":"exception","errorClass":"JsonSyntaxException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/internal/bind/MapTypeAdapterFactory.java","lineNumber":192,"sourceCode":"\n    @Override\n    public Map<K, V> read(JsonReader in) throws IOException {\n      JsonToken peek = in.peek();\n      if (peek == JsonToken.NULL) {\n        in.nextNull();\n        return null;\n      }\n\n      Map<K, V> map = constructor.construct();\n\n      if (peek == JsonToken.BEGIN_ARRAY) {\n        in.beginArray();\n        while (in.hasNext()) {\n          in.beginArray(); // entry array\n          K key = keyTypeAdapter.read(in);\n          V value = valueTypeAdapter.read(in);\n          if (map.containsKey(key)) {\n            throw new JsonSyntaxException(\"duplicate key: \" + key);\n          }\n          map.put(key, value);\n          in.endArray();\n        }\n        in.endArray();\n      } else {\n        in.beginObject();\n        while (in.hasNext()) {\n          JsonReaderInternalAccess.INSTANCE.promoteNameToValue(in);\n          K key = keyTypeAdapter.read(in);\n          V value = valueTypeAdapter.read(in);\n          if (map.containsKey(key)) {\n            throw new JsonSyntaxException(\"duplicate key: \" + key);\n          }\n          map.put(key, value);\n        }\n        in.endObject();\n      }","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/google/gson/blob/8b8628c65699bc4421696183c62ae0c1b9b281dc/gson/src/main/java/com/google/gson/internal/bind/MapTypeAdapterFactory.java#L174-L210","documentation":"Thrown by MapTypeAdapterFactory.Adapter.read() as a JsonSyntaxException when a Map is being deserialized from the JSON-array-of-pairs form (used with complex map key serialization) and two entries deserialize to keys that are equal. The check is map.containsKey(key) before put, so any duplicate key (by .equals) is rejected.","triggerScenarios":"Deserializing JSON shaped as an array of [key, value] pairs into a Map when two pairs produce equal keys. The array form is used when complexMapKeySerialization is enabled or when the runtime key type is non-primitive. Duplicates can arise from key normalization (e.g. \"1\" and 1 both mapping to Integer 1) or genuinely repeated entries.","commonSituations":"Producer emits duplicate keys unintentionally; key type adapter collapses distinct representations to the same key (string vs number); enum keys where aliases map to the same constant; complex key serialization toggled on but data was serialized without dedup; test fixtures with accidental repeats.","solutions":["Fix the source data to remove duplicate keys before serialization.","If duplicates are legitimate (last-wins desired), use a custom TypeAdapter that puts without the containsKey check, or pre-process the JSON to keep only the last occurrence per key.","Verify the key TypeAdapter is not collapsing distinct values to equal keys; adjust the key adapter if so.","If you don't need complex key serialization, disable it so the object form is used (note: object form also rejects duplicates at 205)."],"exampleFix":"// before: JSON has duplicate complex keys -> throws\n// [[\"a\",1],[\"a\",2]]\nType type = new TypeToken<Map<String,Integer>>(){}.getType();\nMap<String,Integer> m = gson.fromJson(json, type);\n\n// after: dedupe source, or use last-wins custom adapter\nMap<String,Integer> m = gson.fromJson(json, type); // once source is deduped\n// or register a last-wins adapter that skips the containsKey check","handlingStrategy":"try-catch","validationCode":"// Dedupe JSON array-of-pairs by key before deserializing into a Map\nJsonArray arr = JsonParser.parseString(json).getAsJsonArray();\nMap<String,JsonElement> seen = new LinkedHashMap<>();\nfor (JsonElement e : arr) {\n  String k = e.getAsJsonArray().get(0).toString();\n  seen.put(k, e.getAsJsonArray().get(1));\n}\n// then build the map manually or serialize seen back to deduped JSON","typeGuard":null,"tryCatchPattern":"try {\n  return gson.fromJson(json, mapType);\n} catch (JsonSyntaxException e) {\n  if (e.getMessage() != null && e.getMessage().startsWith(\"duplicate key:\")) {\n    // last-wins: parse as array of pairs, put without containsKey check\n    return buildMapLastWins(json);\n  }\n  throw e;\n}","preventionTips":["Validate source data for duplicate keys before deserialization.","Ensure key adapters preserve distinctness; avoid collapsing distinct keys.","If duplicates are valid, use a last-wins custom adapter rather than the built-in."],"tags":["json","gson","deserialization","map","duplicate-key","complex-keys"],"analyzedSha":"8b8628c65699bc4421696183c62ae0c1b9b281dc","analyzedAt":"2026-08-04T19:12:22.202Z","schemaVersion":2}