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
- Verify the adapter is registered for exactly the type its read() returns (use TypeToken, not raw Class, for generics).
- Audit the custom TypeAdapter.read() to ensure it constructs/returns an instance assignable to T.
- For generic types, register using a TypeToken captured in an anonymous subclass so generics are preserved.
- 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
- Register adapters using TypeToken (not raw Class) for generic types.
- Write a contract test: fromJson must return an instanceof the target type.
- Avoid unchecked casts inside custom adapters.
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
- Adapter for type with cyclic dependency has been used…
- GSON cannot serialize or deserialize
- GSON ( ) cannot handle
- Attempted to deserialize a java.lang.Class. Forgot to…
- Attempted to serialize java.lang.Class
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)