google/gson · error · JsonParseException

cannot deserialize ${baseType} subtype named ${label}; did y

Error message

cannot deserialize ${baseType} subtype named ${label}; did you forget to register a subtype?

What it means

Thrown during deserialization by RuntimeTypeAdapterFactory when the JSON discriminator value (the label) does not match any label registered via registerSubtype. The adapter looks up the delegate adapter keyed by the label string; a null result means the subtype is unknown to this factory, which is rejected as a security measure (no unregistered/injected types are instantiated).

Source

Thrown at extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java:286

        JsonElement labelJsonElement;
        if (maintainType) {
          labelJsonElement = jsonElement.getAsJsonObject().get(typeFieldName);
        } else {
          labelJsonElement = jsonElement.getAsJsonObject().remove(typeFieldName);
        }

        if (labelJsonElement == null) {
          throw new JsonParseException(
              "cannot deserialize "
                  + baseType
                  + " because it does not define a field named "
                  + typeFieldName);
        }
        String label = labelJsonElement.getAsString();
        @SuppressWarnings("unchecked") // registration requires that subtype extends T
        TypeAdapter<R> delegate = (TypeAdapter<R>) labelToDelegate.get(label);
        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?");

View on GitHub (pinned to 310ac341f2)

Solutions

  1. Register the subtype whose label appears in the JSON: factory.registerSubtype(TheClass, "theLabelFromJson").
  2. Verify label exact spelling and case against the JSON value (labels are case sensitive per the Javadoc).
  3. If forward compatibility is needed, pre-sanitize unknown labels to a safe default before deserializing, or deserialize into a known superset of registered types.
  4. Add a unit test asserting every label the producer can emit is registered on the consumer.

Example fix

// before: JSON has {"type":"Hexagon"} but it is not registered
factory.registerSubtype(Rectangle.class, "Rectangle");
factory.registerSubtype(Circle.class, "Circle");

// after
factory.registerSubtype(Hexagon.class, "Hexagon");
Defensive patterns

Strategy: validation

Validate before calling

// Validate the discriminator label against the registered set before deserializing
Set<String> allowed = Set.of("Rectangle", "Circle", "Diamond");
JsonElement el = JsonParser.parseString(json);
String label = el.isJsonObject() && el.getAsJsonObject().has("type")
    ? el.getAsJsonObject().get("type").getAsString() : null;
if (label == null || !allowed.contains(label)) {
  throw new IllegalArgumentException("Unknown subtype label: " + label);
}

Try / catch

try { gson.fromJson(json, Shape.class); }
catch (JsonParseException e) {
  if (e.getMessage().contains("did you forget to register a subtype")) {
    // log unknown label, fall back to a safe default type or reject the request
  } else throw e;
}

Prevention

When it happens

Trigger: JSON carries a discriminator label that was never registered (e.g. "Hexagon" when only Rectangle/Circle are registered); producer added a new subtype but the consumer's factory was not updated; label case mismatch ("rectangle" vs "Rectangle"); trailing/whitespace differences in the label value.

Common situations: Rolling out a new polymorphic subtype on the server before updating client-side Gson configuration; case-sensitive label mismatch across locales/serializers; tampered or forward-incompatible payload sent by a newer API version; copy of registration list that dropped an entry.

Related errors


AI-assisted analysis of google/gson@310ac341f2 (2026-08-10). Data as JSON: /api/errors/c730bc36a23a19b2. Report an issue: GitHub.