google/gson · error · JsonParseException
cannot serialize {srcType.getName()}; did you forget to regi
Error message
cannot serialize {srcType.getName()}; did you forget to register a subtype? What it means
Thrown during serialization by RuntimeTypeAdapterFactory's write() when the runtime (actual) class of the object being serialized was not registered as a subtype. The adapter looks up value.getClass() in its subtypeToLabel map; an unregistered class cannot be assigned a discriminator label, so serialization is aborted. This is a JsonParseException thrown from toJson/toJsonTree.
Source
Thrown at extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java:303
if (delegate == null) {
throw new JsonParseException(
"cannot deserialize "
+ baseType
+ " subtype named "
+ label
+ "; did you forget to register a subtype?");
}
return delegate.fromJsonTree(jsonElement);
}
@Override
public void write(JsonWriter out, R value) throws IOException {
Class<?> srcType = value.getClass();
String label = subtypeToLabel.get(srcType);
@SuppressWarnings("unchecked") // registration requires that subtype extends T
TypeAdapter<R> delegate = (TypeAdapter<R>) subtypeToDelegate.get(srcType);
if (delegate == null) {
throw new JsonParseException(
"cannot serialize " + srcType.getName() + "; did you forget to register a subtype?");
}
JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject();
if (maintainType) {
jsonElementAdapter.write(out, jsonObject);
return;
}
JsonObject clone = new JsonObject();
if (jsonObject.has(typeFieldName)) {
throw new JsonParseException(
"cannot serialize "
+ srcType.getName()
+ " because it already defines a field named "
+ typeFieldName);
}View on GitHub (pinned to 8b8628c656)
Solutions
- Register the concrete runtime class: factory.registerSubtype(Triangle.class).
- Check value.getClass() at the call site before serializing if the type set is dynamic.
- Avoid anonymous subclasses of registered base types, or register their exact generated names (impractical; prefer named classes).
- If using code generation (AutoValue, protobuf), register the generated subclass, not the base.
Example fix
// before
RuntimeTypeAdapterFactory<Shape> f = RuntimeTypeAdapterFactory.of(Shape.class)
.registerSubtype(Circle.class);
Gson gson = new GsonBuilder().registerTypeAdapterFactory(f).create();
String json = gson.toJson(new Triangle(), Shape.class); // throws
// after
RuntimeTypeAdapterFactory<Shape> f = RuntimeTypeAdapterFactory.of(Shape.class)
.registerSubtype(Circle.class)
.registerSubtype(Triangle.class);
String json = gson.toJson(new Triangle(), Shape.class); Defensive patterns
Strategy: type-guard
Validate before calling
// Validate the runtime class is registered before serializing
Set<Class<?>> registered = Set.of(Circle.class, Rectangle.class);
Object value = new Triangle();
if (!registered.contains(value.getClass())) {
throw new IllegalArgumentException("Class not registered: " + value.getClass());
}
String json = gson.toJson(value, Shape.class); Type guard
static boolean isRegisteredSubtype(Object value, Set<Class<?>> registered) {
return value != null && registered.contains(value.getClass());
} Try / catch
try {
String json = gson.toJson(value, Shape.class);
} catch (JsonParseException e) {
if (e.getMessage().contains("cannot serialize") && e.getMessage().contains("register a subtype")) {
// value's runtime class not registered; register it or reject
} else throw e;
} Prevention
- Always serialize via gson.toJson(obj, BaseType.class) and ensure the concrete class is registered.
- Avoid anonymous subclasses of registered base types; use named classes.
- If using code generation (AutoValue, protobuf), register the generated subclass.
- Keep a registry/enum of allowed concrete types and check membership before serializing.
When it happens
Trigger: Calling gson.toJson(new Triangle(), Shape.class) when only Circle and Rectangle were registered; passing a subclass instance whose parent was registered but the concrete class was not (registration is by exact class, not by assignability unless recognizeSubtypes() is set, and even then write() uses the exact runtime class); instantiating an anonymous subclass of a registered type.
Common situations: Adding a new subclass but forgetting to register it; serializing an anonymous or lambda-derived subclass of a registered type; using a mocking framework (Mockito) that creates a synthetic subclass; protobuf/AutoValue generated subclasses that differ from the registered class.
Related errors
- cannot deserialize {baseType} subtype named {label}; did you
- cannot serialize {srcType.getName()} because it already defi
- types and labels must be unique
- cannot deserialize {baseType} because it does not define a f
- Deserialization is unsupported
AI-assisted analysis of google/gson@8b8628c656 (2026-08-04).
Data as JSON: /data/errors/6b2f33ec193db8a7.json.
Report an issue: GitHub.