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 when more than one lower bound is supplied. Although java.lang.reflect.WildcardType.getLowerBounds() formally returns an array, real Java source only supports a single lower bound per wildcard (<? super T>); multiple lower bounds are not expressible. Gson rejects the impossible case rather than silently dropping bounds (GsonTypes.java:626).

Solutions

  1. Pass exactly one lower bound (or none) when constructing the wildcard; combine multiple candidate bounds into a single common supertype first.
  2. If you are aggregating bounds, intersect them at the upper bound instead and use an upper-bounded wildcard.
  3. Avoid building WildcardType manually; prefer TypeToken/TypeToken.getParameterized which produce correct wildcards.

Example fix

// before
new WildcardTypeImpl(new Type[]{Object.class}, new Type[]{String.class, Number.class});
// after
new WildcardTypeImpl(new Type[]{Object.class}, new Type[]{String.class});
Defensive patterns

Strategy: validation

Validate before calling

if (lowerBounds != null && lowerBounds.length > 1) throw new IllegalArgumentException("only one lower bound allowed");

Type guard

static boolean singleLowerBound(Type[] lbs) { return lbs == null || lbs.length <= 1; }

Prevention

When it happens

Trigger: Constructing a WildcardTypeImpl with a lowerBounds array of length > 1; typically from hand-built Type factories, bridging libraries, or reflective code that aggregates bounds from multiple type variables.

Common situations: Custom TypeAdapterFactory code that programmatically builds wildcard types; migrating from libraries that expose getLowerBounds() arrays verbatim; test fixtures that synthesize malformed wildcards.

Related errors


AI-assisted analysis of google/gson@310ac341f2 (2026-08-10). Data as JSON: /api/errors/481e0800b6fd9974. Report an issue: GitHub.

Appendix: 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 310ac341f2)