google/gson · error · ClassCastException

Type adapter ' ' returned wrong type; requested but got…

Error message

Type adapter '${typeAdapter}' returned wrong type; requested ${typeOfT.getRawType()} but got instance of ${object.getClass()}
Verify that the adapter was registered for the correct type.

What it means

Thrown by Gson.fromJson(JsonReader, TypeToken) right after a TypeAdapter.read returns: if the returned object is non-null but is not an instance of the requested (boxed) raw type, a ClassCastException is thrown naming the adapter, the requested type, and the actual class. This catches buggy/misregistered adapters that return the wrong type, failing fast instead of propagating a ClassCastException later at an opaque site.

Solutions

  1. Verify the adapter is registered for exactly the type its read() returns (use TypeToken, not raw Class, for generics).
  2. Audit the custom TypeAdapter.read() to ensure it constructs/returns an instance assignable to T.
  3. For generic types, register using a TypeToken captured in an anonymous subclass so generics are preserved.
  4. Write a focused unit test asserting gson.fromJson(json, Type) returns an instanceof the expected type.

Example fix

// before: adapter registered for Foo returns Bar
class FooAdapter extends TypeAdapter<Foo> {
  public Foo read(JsonReader in) { return new Bar(); } // wrong type
}

// after
public Foo read(JsonReader in) { return new Foo(); }
Defensive patterns

Strategy: type-guard

Validate before calling

// Unit-level guard: assert the adapter returns the right type
Object result = adapter.read(new JsonReader(new StringReader(json)));
if (!expectedRawType.isInstance(result)) {
  throw new AssertionError("Adapter returned " + result.getClass());
}

Type guard

// Narrow the result of fromJson defensively
static <T> Optional<T> tryAs(T value, Class<T> type) {
  return type.isInstance(value) ? Optional.of(type.cast(value)) : Optional.empty();
}

Try / catch

try { T v = gson.fromJson(reader, typeOfT); }
catch (ClassCastException e) {
  if (e.getMessage().contains("returned wrong type")) {
    // the registered adapter is wrong; fix registration and retry
  } else throw e;
}

Prevention

When it happens

Trigger: A custom TypeAdapter registered for type A whose read() returns an instance of B; registering an adapter for the generic-erased raw type while read() returns a subtype incompatible with the declared TypeToken; reusing one adapter for multiple types via unchecked casts; adapter returning a Map where a POJO is expected.

Common situations: Unchecked cast inside a custom adapter; adapter written for a different (but name-similar) type; raw-type registration losing generics (List vs List<Foo>); copy-paste of an adapter without updating its target type.

Related errors


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

Appendix: source

Thrown at gson/src/main/java/com/google/gson/Gson.java:1106

      throws JsonIOException, JsonSyntaxException {
    boolean isEmpty = true;
    Strictness oldStrictness = reader.getStrictness();

    if (this.strictness != null) {
      reader.setStrictness(this.strictness);
    } else if (reader.getStrictness() == Strictness.LEGACY_STRICT) {
      // For backward compatibility change to LENIENT if reader has default strictness LEGACY_STRICT
      reader.setStrictness(Strictness.LENIENT);
    }

    try {
      JsonToken unused = reader.peek();
      isEmpty = false;
      TypeAdapter<T> typeAdapter = getAdapter(typeOfT);
      T object = typeAdapter.read(reader);
      Class<?> expectedTypeWrapped = Primitives.wrap(typeOfT.getRawType());
      if (object != null && !expectedTypeWrapped.isInstance(object)) {
        throw new ClassCastException(
            "Type adapter '"
                + typeAdapter
                + "' returned wrong type; requested "
                + typeOfT.getRawType()
                + " but got instance of "
                + object.getClass()
                + "\nVerify that the adapter was registered for the correct type.");
      }
      return object;
    } catch (EOFException e) {
      /*
       * For compatibility with JSON 1.5 and earlier, we return null for empty
       * documents instead of throwing.
       */
      if (isEmpty) {
        return null;
      }
      throw new JsonSyntaxException(e);

View on GitHub (pinned to 310ac341f2)