google/gson · error · ClassCastException
Type adapter '{typeAdapter}' returned wrong type; requested
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) after the type adapter's read() returns, when the returned object is non-null but is not an instance of the requested type (after boxing primitives). This means a custom TypeAdapter returned the wrong class, breaking the TypeAdapter<T> contract. It is a ClassCastException, surfaced directly (not wrapped) from fromJson.
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 8b8628c656)
Solutions
- Verify the TypeAdapter is registered for the exact type it produces (e.g. register it under Date.class only if read() returns a Date).
- Make read() return the declared T; convert internally before returning.
- If using generics, use TypeToken to capture the parameterized type and ensure the adapter's output matches.
- Add a unit test asserting the returned object's class equals the requested type.
Example fix
// before: adapter registered for Date returns a String
class BadDateAdapter extends TypeAdapter<Date> {
public Date read(JsonReader r) throws IOException { return (Date)(Object)r.nextString(); } // wrong
}
// after: convert to the declared return type
class GoodDateAdapter extends TypeAdapter<Date> {
public Date read(JsonReader r) throws IOException { return new Date(r.nextLong()); }
public void write(JsonWriter w, Date v) throws IOException { w.value(v.getTime()); }
} Defensive patterns
Strategy: type-guard
Validate before calling
// After a custom adapter read, verify the returned type matches
TypeAdapter<Date> adapter = ...;
Date result = adapter.read(reader);
if (result != null && !(result instanceof Date)) {
throw new IllegalStateException("Adapter returned " + result.getClass());
} Type guard
static <T> boolean returnsCorrectType(TypeAdapter<T> adapter, JsonReader r, Class<T> expected)
throws IOException {
T v = adapter.read(r);
return v == null || expected.isInstance(v);
} Try / catch
try {
Foo f = gson.fromJson(json, TypeToken.get(Foo.class));
} catch (ClassCastException e) {
if (e.getMessage().contains("returned wrong type")) {
// an adapter is registered for the wrong type; fix the registration
} else throw e;
} Prevention
- Register each TypeAdapter under the exact type its read() returns.
- Add a unit test asserting the adapter's output class equals the requested type.
- Avoid unchecked casts inside adapters; convert explicitly before returning.
- When using @JsonAdapter, ensure the annotation targets the matching class.
When it happens
Trigger: A custom TypeAdapter<Date> whose read() returns a String or Long; a TypeAdapter registered for type A but internally producing B; raw-type misuse where a TypeAdapter is registered with a raw class but produces a generic-substituted type; unsafe casts inside an adapter leaking an incompatible object.
Common situations: Adapters copied from examples targeting a different type than the one registered; generics erasure hiding a mismatch at compile time; an adapter that delegates to another adapter returning a broader type; @JsonAdapter pointing at an adapter written for a different class; refactoring a model without updating its adapter.
Related errors
- GSON ({GsonBuildConfig.VERSION}) cannot handle {type}
- GSON cannot serialize or deserialize {type}
- JSON document was not fully consumed.
- Adapter for type with cyclic dependency has been used before
- cannot deserialize {baseType} because it does not define a f
AI-assisted analysis of google/gson@8b8628c656 (2026-08-04).
Data as JSON: /data/errors/561455962f6f967f.json.
Report an issue: GitHub.