{"record":{"id":"08ee0d763321b724","repo":"google/gson","slug":"cannot-serialize-srctype-getname-because-it-a","errorCode":null,"errorMessage":"cannot serialize ${srcType.getName()} because it already defines a field named ${typeFieldName}","messagePattern":"cannot serialize (.+?) because it already defines a field named (.+?)","errorType":"exception","errorClass":"JsonParseException","httpStatus":null,"severity":"error","filePath":"extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java","lineNumber":316,"sourceCode":"        Class<?> srcType = value.getClass();\n        String label = subtypeToLabel.get(srcType);\n        @SuppressWarnings(\"unchecked\") // registration requires that subtype extends T\n        TypeAdapter<R> delegate = (TypeAdapter<R>) subtypeToDelegate.get(srcType);\n        if (delegate == null) {\n          throw new JsonParseException(\n              \"cannot serialize \" + srcType.getName() + \"; did you forget to register a subtype?\");\n        }\n        JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject();\n\n        if (maintainType) {\n          jsonElementAdapter.write(out, jsonObject);\n          return;\n        }\n\n        JsonObject clone = new JsonObject();\n\n        if (jsonObject.has(typeFieldName)) {\n          throw new JsonParseException(\n              \"cannot serialize \"\n                  + srcType.getName()\n                  + \" because it already defines a field named \"\n                  + typeFieldName);\n        }\n        clone.add(typeFieldName, new JsonPrimitive(label));\n\n        for (Map.Entry<String, JsonElement> e : jsonObject.entrySet()) {\n          clone.add(e.getKey(), e.getValue());\n        }\n        jsonElementAdapter.write(out, clone);\n      }\n    }.nullSafe();\n  }\n}\n","sourceCodeStart":298,"sourceCodeEnd":332,"githubUrl":"https://github.com/google/gson/blob/310ac341f2f92a454b229bf21f70d2d18b2b6db7/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java#L298-L332","documentation":"Thrown during serialization by RuntimeTypeAdapterFactory (when maintainType is false) if the subtype being serialized already serializes a field whose name collides with the configured typeFieldName. Because the factory prepends its own discriminator field with that exact name, a collision would overwrite or shadow the real field, so it aborts with a JsonParseException. It protects data integrity of the discriminator versus a model field.","triggerScenarios":"The subtype class declares a field literally named \"type\" (the default discriminator); typeFieldName was customized to a name that the model already uses (e.g. \"kind\", \"id\"); a parent class introduces a field that collides after the factory was configured.","commonSituations":"Default typeFieldName \"type\" clashes with a domain field; renaming the discriminator to something already used elsewhere in the model; inheriting a base class that already has the conflicting field.","solutions":["Pick a typeFieldName that does not collide with any serialized field, e.g. RuntimeTypeAdapterFactory.of(Base.class, \"__type\").","Rename or @SerializedName the conflicting domain field to a non-colliding key.","If you must keep the same name, use of(Base.class, typeFieldName, true) (maintainType=true) so the factory does not inject/clone the discriminator."],"exampleFix":"// before\nclass Event { String type; } // collides with default discriminator\nRuntimeTypeAdapterFactory.of(Event.class); // \"type\"\n\n// after\nRuntimeTypeAdapterFactory.of(Event.class, \"@type\");","handlingStrategy":"validation","validationCode":"// Detect field-name collision with the discriminator up front\nString typeFieldName = \"type\";\nfor (Field f : subtypeClass.getDeclaredFields()) {\n  String jsonName = f.isAnnotationPresent(SerializedName.class)\n      ? f.getAnnotation(SerializedName.class).value() : f.getName();\n  if (jsonName.equals(typeFieldName)) {\n    throw new IllegalStateException(\"Field '\" + jsonName + \"' collides with discriminator\");\n  }\n}","typeGuard":null,"tryCatchPattern":"try { gson.toJson(obj, Shape.class); }\ncatch (JsonParseException e) {\n  if (e.getMessage().contains(\"already defines a field named\")) {\n    // switch typeFieldName or rename the field\n  } else throw e;\n}","preventionTips":["Choose a discriminator name unlikely to collide (e.g. \"@type\").","Run a smoke serialization test for each registered subtype.","If the field name must match, use maintainType=true."],"tags":["runtime-type-adapter","polymorphism","serialization","field-collision"],"backgroundTag":null,"analyzedSha":"310ac341f2f92a454b229bf21f70d2d18b2b6db7","analyzedAt":"2026-08-10T02:58:47.455Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}