google/gson · error · IllegalArgumentException
GSON cannot serialize or deserialize {type}
Error message
GSON cannot serialize or deserialize {type} What it means
Thrown by Gson.getDelegateAdapter(skipPast, type) when the skipPast factory WAS found among the registered factories, but no factory AFTER it returns a non-null adapter for the type. getDelegateAdapter is the standard way for a custom TypeAdapterFactory to obtain the 'default' adapter for a type (skipping itself); if there is no default, Gson gives up with this IllegalArgumentException.
Source
Thrown at gson/src/main/java/com/google/gson/Gson.java:498
boolean skipPastFound = false;
for (TypeAdapterFactory factory : factories) {
if (!skipPastFound) {
@SuppressWarnings("ReferenceEquality")
boolean isSkipPast = factory == skipPast;
if (isSkipPast) {
skipPastFound = true;
}
continue;
}
TypeAdapter<T> candidate = factory.create(this, type);
if (candidate != null) {
return candidate;
}
}
if (skipPastFound) {
throw new IllegalArgumentException("GSON cannot serialize or deserialize " + type);
} else {
// Probably a factory from @JsonAdapter on a field
return getAdapter(type);
}
}
/**
* This method serializes the specified object into its equivalent representation as a tree of
* {@link JsonElement}s. This method should be used when the specified object is not a generic
* type. This method uses {@link Class#getClass()} to get the type for the specified object, but
* the {@code getClass()} loses the generic type information because of the Type Erasure feature
* of Java. Note that this method works fine if any of the object fields are of generic type, just
* the object itself should not be of a generic type. If the object is of generic type, use {@link
* #toJsonTree(Object, Type)} instead.
*
* @param src the object for which JSON representation is to be created
* @return JSON representation of {@code src}.
* @since 1.4View on GitHub (pinned to 8b8628c656)
Solutions
- Register a concrete TypeAdapter for the type so the delegate search succeeds (the custom factory will then delegate to it).
- Ensure the custom factory is NOT the last registered factory; there must be a factory after it (Gson's built-ins usually satisfy this, unless they cannot handle the type).
- If reflection is the cause, fix accessibility (InstanceCreator, add-opens) as in error 13.
- Handle the null/exception path in your factory and provide a fallback adapter rather than calling getDelegateAdapter unconditionally.
Example fix
// before: custom factory delegates but no default exists for the type
class MyFactory implements TypeAdapterFactory {
public <T> TypeAdapter<T> create(Gson g, TypeToken<T> t) {
TypeAdapter<T> d = p.getDelegateAdapter(this, t); // throws if no factory after this handles t
return d;
}
}
// after: register a real adapter so delegation succeeds, and guard
class MyFactory implements TypeAdapterFactory {
public <T> TypeAdapter<T> create(Gson p, TypeToken<T> t) {
TypeAdapter<T> d = p.getDelegateAdapter(this, t);
return d == null ? null : new MyWrapper<>(d);
}
}
Gson gson = new GsonBuilder()
.registerTypeAdapter(NoDefaultCtor.class, new NoDefaultCtorIC())
.registerTypeAdapterFactory(new MyFactory())
.create(); Defensive patterns
Strategy: try-catch
Validate before calling
// In a delegating factory, check before calling getDelegateAdapter
TypeAdapter<?> probe = null;
try {
probe = gson.getDelegateAdapter(this, type);
} catch (IllegalArgumentException e) {
// no default; return null so other factories can run
return null;
} Try / catch
try {
TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
return new MyWrapper<>(delegate);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("cannot serialize or deserialize")) {
return null; // let other factories handle it, or register a concrete adapter
} else throw e;
} Prevention
- Never place a delegating factory last; ensure factories follow it (Gson's built-ins usually do).
- Register concrete adapters for types that lack a reflective default.
- Guard getDelegateAdapter with try/catch and return null to fall through gracefully.
- Fix accessibility (InstanceCreator, add-opens) for types Gson cannot reflect.
When it happens
Trigger: A custom factory calls gson.getDelegateAdapter(this, type) but the type is one Gson cannot handle reflectively (no constructor, filtered, JDK-inaccessible), and no other factory covers it; ordering mistake where the custom factory is registered last so there are no factories after it to delegate to; delegating to a type that should have had its own adapter registered.
Common situations: Custom wrapper factories (logging, stats, caching) that delegate to the default adapter; the wrapped type lacks a default binding; JPMS reflection blocks; the user forgot to registerTypeAdapter for a type that only the custom factory would have routed to; factory registration order placing the delegating factory at the end.
Related errors
- GSON ({GsonBuildConfig.VERSION}) cannot handle {type}
- Type adapter '{typeAdapter}' returned wrong type; requested
- Adapter for type with cyclic dependency has been used before
- Class {typeAdapter.getClass().getName()} does not implement
- Cannot override built-in adapter for {type}
AI-assisted analysis of google/gson@8b8628c656 (2026-08-04).
Data as JSON: /data/errors/b574cbb693b2bb7f.json.
Report an issue: GitHub.