google/gson · error · IllegalArgumentException
GSON cannot serialize or deserialize
Error message
GSON cannot serialize or deserialize ${type} What it means
Thrown by Gson.getDelegateAdapter(TypeAdapterFactory skipPast, TypeToken) when, after skipping past the specified factory, no subsequent factory produces an adapter for the type. This is the path used by custom factories that delegate to the 'next' adapter; if there is no next adapter the type cannot be (de)serialized and an IllegalArgumentException is raised.
Solutions
- Register the delegating TypeAdapterFactory BEFORE the built-in/fallback factory it wants to delegate to (use registerTypeAdapterFactory early).
- Make sure there is a factory after skipPast able to handle the type.
- If you do not actually need delegation, call getAdapter(type) instead of getDelegateAdapter(this, type).
- Restructure so the decorator returns a non-null adapter itself rather than relying on a later factory.
Example fix
// before: decorator registered last -> no delegate new GsonBuilder() .registerTypeAdapter(Foo.class, defaultFooAdapter) .registerTypeAdapterFactory(decoratorThatDelegates) // last -> throws .create(); // after: decorator first so delegate exists after it new GsonBuilder() .registerTypeAdapterFactory(decoratorThatDelegates) .registerTypeAdapter(Foo.class, defaultFooAdapter) .create();
Defensive patterns
Strategy: validation
Validate before calling
// Ensure the delegating factory is registered before fallbacks // Order matters: register decorator FIRST, then the adapter it delegates to. new GsonBuilder() .registerTypeAdapterFactory(decorator) // earlier .registerTypeAdapter(Foo.class, fallback) // later -> delegate exists .create();
Try / catch
try { gson.getDelegateAdapter(this, type); }
catch (IllegalArgumentException e) {
if (e.getMessage().contains("cannot serialize or deserialize")) {
// fall back to getAdapter(type) or restructure factory order
} else throw e;
} Prevention
- Register decorating factories before the adapters they wrap.
- Prefer getAdapter(type) when delegation is not required.
- Verify factory ordering in a unit test.
When it happens
Trigger: A custom factory calling gson.getDelegateAdapter(this, type) when it is the last factory in the chain; delegating past a factory for a type only that factory handled; skipPast factory not actually registered (falls back to getAdapter, so this specific throw needs skipPastFound && no later match).
Common situations: Ordering mistake: a delegating factory registered after all relevant built-ins; a decorator factory that should wrap the default adapter but is placed last; manually iterating factories and skipping too far.
Related errors
- Adapter for type with cyclic dependency has been used…
- GSON ( ) cannot handle
- Type adapter ' ' returned wrong type; requested but got…
- 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/8daba4249f09f47f.
Report an issue: GitHub.
Appendix: 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 310ac341f2)