{"record":{"id":"dc40bb14e94ea9ae","repo":"google/gson","slug":"cannot-serialize-srctype-getname-did-you-for","errorCode":null,"errorMessage":"cannot serialize ${srcType.getName()}; did you forget to register a subtype?","messagePattern":"cannot serialize (.+?); did you forget to register a subtype\\?","errorType":"exception","errorClass":"JsonParseException","httpStatus":null,"severity":"error","filePath":"extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java","lineNumber":303,"sourceCode":"        if (delegate == null) {\n          throw new JsonParseException(\n              \"cannot deserialize \"\n                  + baseType\n                  + \" subtype named \"\n                  + label\n                  + \"; did you forget to register a subtype?\");\n        }\n        return delegate.fromJsonTree(jsonElement);\n      }\n\n      @Override\n      public void write(JsonWriter out, R value) throws IOException {\n        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        }","sourceCodeStart":285,"sourceCodeEnd":321,"githubUrl":"https://github.com/google/gson/blob/310ac341f2f92a454b229bf21f70d2d18b2b6db7/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java#L285-L321","documentation":"Thrown during serialization by RuntimeTypeAdapterFactory when the runtime class of the object being written (value.getClass()) was never registered as a subtype. Registration keys on the exact runtime class, so an unregistered subclass of a registered type also fails. The adapter cannot pick a label, so it throws a JsonParseException. This is intentional: only explicitly allow-listed types are serialized.","triggerScenarios":"Serializing a concrete subtype that was not registerSubtype'd; serializing via gson.toJson(obj, Shape.class) where obj is a subclass not registered; using the factory for the base type but passing a sibling subclass; subclass instances created by a different module/library.","commonSituations":"New subclass added to the domain model but the Gson factory wiring was not updated; registering a parent class and expecting subclasses to be covered (they are not, by default); serialize called with a proxied/mock subclass whose class differs from the registered one.","solutions":["Register the exact runtime class: factory.registerSubtype(obj.getClass(), label).","If you want subtypes auto-handled, ensure every concrete subclass that can appear at runtime is explicitly registered (registration is per exact class).","Confirm you serialize using the base type token expected by the factory (e.g. gson.toJson(obj, Shape.class)).","Centralize registration next to the class hierarchy definition so adding a subclass forces an update."],"exampleFix":"// before\nfactory.registerSubtype(Shape.class, \"Shape\");\ngson.toJson(new Circle(), Shape.class); // Circle not registered -> throws\n\n// after\nfactory.registerSubtype(Circle.class, \"Circle\");\ngson.toJson(new Circle(), Shape.class);","handlingStrategy":"validation","validationCode":"// Ensure the runtime class is registered before serializing\nSet<Class<?>> registered = Set.of(Circle.class, Rectangle.class);\nObject value = /* ... */;\nif (!registered.contains(value.getClass())) {\n  throw new IllegalArgumentException(\"Unregistered subtype: \" + value.getClass());\n}\ngson.toJson(value, Shape.class);","typeGuard":null,"tryCatchPattern":"try { gson.toJson(obj, Shape.class); }\ncatch (JsonParseException e) {\n  if (e.getMessage().contains(\"cannot serialize\") && e.getMessage().contains(\"register a subtype\")) {\n    // register and retry, or reject the object\n  } else throw e;\n}","preventionTips":["Register every concrete runtime class, not just the parent.","Serialize using the base type token the factory expects (Shape.class).","Co-locate registration with the subclass definitions so adding a class forces an update."],"tags":["runtime-type-adapter","polymorphism","serialization","registration"],"backgroundTag":null,"analyzedSha":"310ac341f2f92a454b229bf21f70d2d18b2b6db7","analyzedAt":"2026-08-10T02:58:47.455Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}