{"record":{"id":"04a579d7e7ab3dc8","repo":"google/gson","slug":"types-and-labels-must-be-unique","errorCode":null,"errorMessage":"types and labels must be unique","messagePattern":"types and labels must be unique","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java","lineNumber":224,"sourceCode":"  @CanIgnoreReturnValue\n  public RuntimeTypeAdapterFactory<T> recognizeSubtypes() {\n    this.recognizeSubtypes = true;\n    return this;\n  }\n\n  /**\n   * Registers {@code type} identified by {@code label}. Labels are case sensitive.\n   *\n   * @throws IllegalArgumentException if either {@code type} or {@code label} have already been\n   *     registered on this type adapter.\n   */\n  @CanIgnoreReturnValue\n  public RuntimeTypeAdapterFactory<T> registerSubtype(Class<? extends T> type, String label) {\n    if (type == null || label == null) {\n      throw new NullPointerException();\n    }\n    if (subtypeToLabel.containsKey(type) || labelToSubtype.containsKey(label)) {\n      throw new IllegalArgumentException(\"types and labels must be unique\");\n    }\n    labelToSubtype.put(label, type);\n    subtypeToLabel.put(type, label);\n    return this;\n  }\n\n  /**\n   * Registers {@code type} identified by its {@link Class#getSimpleName simple name}. Labels are\n   * case sensitive.\n   *\n   * @throws IllegalArgumentException if either {@code type} or its simple name have already been\n   *     registered on this type adapter.\n   */\n  @CanIgnoreReturnValue\n  public RuntimeTypeAdapterFactory<T> registerSubtype(Class<? extends T> type) {\n    return registerSubtype(type, type.getSimpleName());\n  }\n","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/google/gson/blob/310ac341f2f92a454b229bf21f70d2d18b2b6db7/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java#L206-L242","documentation":"Thrown by RuntimeTypeAdapterFactory.registerSubtype(Class, String) when the subtype class or the label string has already been registered on the same factory. The factory keeps two maps (subtypeToLabel and labelToSubtype) and rejects any duplicate on either side to keep the type<->label mapping strictly one-to-one. This is a configuration-time IllegalArgumentException, fired before any serialization occurs.","triggerScenarios":"Calling registerSubtype(SameClass, ...) twice; calling registerSubtype(ClassA, \"foo\") and registerSubtype(ClassB, \"foo\") (duplicate label); calling the single-arg registerSubtype(Class) for two classes whose getSimpleName() collide; re-registering after reusing one factory instance across builds.","commonSituations":"Two inner classes share a simple name (e.g. two Foo$Bar); a label typo reuses an existing discriminator; building the factory inside a loop or helper that runs more than once; copy-pasting registration blocks; mixing label-based and simple-name registration.","solutions":["Search your registration calls for the duplicated class or label name reported in the failure.","If two classes share a simple name, pass an explicit unique label as the second argument to registerSubtype.","Make sure the RuntimeTypeAdapterFactory is constructed fresh per GsonBuilder.create() and not reused/shared across builds.","Build the label set programmatically and assert uniqueness before registering (e.g. collect labels into a Set)."],"exampleFix":"// before\nfactory.registerSubtype(Circle.class);\nfactory.registerSubtype(Circle.class); // duplicate class -> throws\n\n// after\nfactory.registerSubtype(Circle.class, \"circle\");\nfactory.registerSubtype(Square.class, \"square\");","handlingStrategy":"validation","validationCode":"// Before building the factory, assert no duplicate class or label\nSet<Class<?>> classes = new HashSet<>();\nSet<String> labels = new HashSet<>();\nfor (var reg : registrations) {\n  if (!classes.add(reg.type) || !labels.add(reg.label)) {\n    throw new IllegalStateException(\"Duplicate subtype registration: \" + reg);\n  }\n}\n// then safely call factory.registerSubtype(reg.type, reg.label)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Construct a fresh RuntimeTypeAdapterFactory per Gson build; do not reuse the same instance across create() calls.","Prefer explicit labels over simple names when classes may share names.","Keep all registerSubtype calls in one place adjacent to the type hierarchy."],"tags":["runtime-type-adapter","polymorphism","configuration","gson-extras"],"backgroundTag":null,"analyzedSha":"310ac341f2f92a454b229bf21f70d2d18b2b6db7","analyzedAt":"2026-08-10T02:58:47.455Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}