google/gson · error · IllegalArgumentException
At most one lower bound is supported
Error message
At most one lower bound is supported
What it means
Thrown by WildcardTypeImpl (GsonTypes) when more than one lower bound is supplied. Java wildcards (e.g. ? super T) allow only a single lower bound syntactically; the WildcardType interface permits an array but Gson deliberately supports at most one (see JDK-8250660). Constructing a wildcard with two lower bounds is rejected because it cannot be expressed in source.
Source
Thrown at gson/src/main/java/com/google/gson/internal/GsonTypes.java:627
public String toString() {
return typeToString(componentType) + "[]";
}
}
/**
* The WildcardType interface supports multiple upper bounds and multiple lower bounds. We only
* support what the target Java version supports - at most one bound, see also
* https://bugs.openjdk.java.net/browse/JDK-8250660. If a lower bound is set, the upper bound must
* be Object.class.
*/
private static final class WildcardTypeImpl implements WildcardType {
private final Type upperBound;
private final Type lowerBound;
WildcardTypeImpl(Type[] upperBounds, Type[] lowerBounds) {
if (lowerBounds.length > 1) {
throw new IllegalArgumentException("At most one lower bound is supported");
}
if (upperBounds.length != 1) {
throw new IllegalArgumentException("Exactly one upper bound must be specified");
}
if (lowerBounds.length == 1) {
requireNonNull(lowerBounds[0]);
checkNotPrimitive(lowerBounds[0]);
if (upperBounds[0] != Object.class) {
throw new IllegalArgumentException(
"When lower bound is specified, upper bound must be Object");
}
this.lowerBound = canonicalize(lowerBounds[0]);
this.upperBound = Object.class;
} else {
requireNonNull(upperBounds[0]);
checkNotPrimitive(upperBounds[0]);View on GitHub (pinned to 8b8628c656)
Solutions
- Ensure any custom WildcardType.getLowerBounds() returns at most one element; keep only the first bound.
- Avoid building wildcard types by hand; use Gson's Types.supertypeOf(singleBound) or Types.subtypeOf(singleBound).
- If the extra bounds are genuine, the type cannot be modeled as a single wildcard; split into separate types or widen to a non-wildcard parameterized type.
Example fix
// before: custom WildcardType with two lower bounds
public Type[] getLowerBounds() { return new Type[] { String.class, Number.class }; }
// after: single lower bound only
public Type[] getLowerBounds() { return new Type[] { String.class }; } Defensive patterns
Strategy: validation
Validate before calling
static Type normalizeWildcard(WildcardType w) {
Type[] lb = w.getLowerBounds();
if (lb.length > 1) {
// keep only the first lower bound
return com.google.gson.internal.$Gson$Types.supertypeOf(lb[0]);
}
return w;
} Type guard
static boolean hasAtMostOneLowerBound(WildcardType w) {
return w.getLowerBounds().length <= 1;
} Try / catch
try {
canonicalize(wildcardType);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("lower bound")) {
wildcardType = normalizeWildcard(wildcardType);
} else throw e;
} Prevention
- Avoid hand-building WildcardType; use Gson's supertypeOf/subtypeOf helpers.
- If you must, guarantee getLowerBounds().length <= 1.
- Unit-test custom Type implementations against Gson's canonicalizer.
When it happens
Trigger: Calling a wildcard-construction path (subtypeOf/supertypeOf or internal canonicalize of a WildcardType) with lowerBounds.length > 1. Happens when a hand-built WildcardType reports multiple lower bounds, or a reflective Type from a non-standard JVM/library advertises two lower bounds.
Common situations: Custom WildcardType implementations returning arrays of length > 1 from getLowerBounds(); reflection on synthetic/bridge types produced by older JVMs or annotation processors; interop with libraries that build wildcard types permissively.
Related errors
- Exactly one upper bound must be specified
- When lower bound is specified, upper bound must be Object
- Primitive type is not allowed
- Must specify owner type for {rawType}
- TypeToken type argument must not contain a type variable; ca
AI-assisted analysis of google/gson@8b8628c656 (2026-08-04).
Data as JSON: /data/errors/481e0800b6fd9974.json.
Report an issue: GitHub.