google/gson · error · IllegalArgumentException

Type argument " + typeArgument + " does not satisfy bounds f

Error message

Type argument " + typeArgument + " does not satisfy bounds for type variable " + typeVariable + " declared by " + rawType

What it means

Thrown by TypeToken.getParameterized after checking each type argument against the bounds of the corresponding type variable (TypeVariable.getBounds()). If the raw type argument does not satisfy an upper bound (e.g. <T extends Comparable<T>>), getParameterized rejects it so that downstream serialization does not fail in confusing ways or produce a ClassCastException.

Source

Thrown at gson/src/main/java/com/google/gson/reflect/TypeToken.java:432

    // Check for this here to avoid misleading exception thrown by ParameterizedTypeImpl
    if (GsonTypes.requiresOwnerType(rawType)) {
      throw new IllegalArgumentException(
          "Raw type "
              + rawClass.getName()
              + " is not supported because it requires specifying an owner type");
    }

    for (int i = 0; i < expectedArgsCount; i++) {
      Type typeArgument =
          Objects.requireNonNull(typeArguments[i], "Type argument must not be null");
      Class<?> rawTypeArgument = GsonTypes.getRawType(typeArgument);
      TypeVariable<?> typeVariable = typeVariables[i];

      for (Type bound : typeVariable.getBounds()) {
        Class<?> rawBound = GsonTypes.getRawType(bound);

        if (!rawBound.isAssignableFrom(rawTypeArgument)) {
          throw new IllegalArgumentException(
              "Type argument "
                  + typeArgument
                  + " does not satisfy bounds for type variable "
                  + typeVariable
                  + " declared by "
                  + rawType);
        }
      }
    }

    return new TypeToken<>(GsonTypes.newParameterizedTypeWithOwner(null, rawClass, typeArguments));
  }

  /**
   * Gets type literal for the array type whose elements are all instances of {@code componentType}.
   */
  public static TypeToken<?> getArray(Type componentType) {
    return new TypeToken<>(GsonTypes.arrayOf(componentType));

View on GitHub (pinned to 8b8628c656)

Solutions

  1. Pass a type argument that satisfies the bound (e.g. for <T extends Number> pass Integer.class, BigDecimal.class, etc.).
  2. Loosen or remove the type bound on the generic class if the constraint is no longer correct.
  3. Validate the candidate Class against the bound programmatically before calling getParameterized.
  4. If the bound is intentional but you must accept arbitrary types, redesign the API to work with Object/raw types outside Gson.

Example fix

// before
class Box<T extends Number> { T value; }
TypeToken.getParameterized(Box.class, String.class); // throws

// after
TypeToken.getParameterized(Box.class, Integer.class);
Defensive patterns

Strategy: validation

Validate before calling

boolean satisfiesBounds(Class<?> rawClass, Type typeArg) {
  Class<?> rawArg = com.google.gson.internal.GsonTypes.getRawType(typeArg);
  for (java.lang.reflect.TypeVariable<?> tv : rawClass.getTypeParameters()) {
    for (Type bound : tv.getBounds()) {
      Class<?> rawBound = com.google.gson.internal.GsonTypes.getRawType(bound);
      if (!rawBound.isAssignableFrom(rawArg)) return false;
    }
  }
  return true;
}
// call before TypeToken.getParameterized(rawClass, typeArg)

Prevention

When it happens

Trigger: Passing a type argument that violates the declared bound, e.g. class Box<T extends Number>{}; TypeToken.getParameterized(Box.class, String.class). The bound Number is not assignable from String, so the check at TypeToken.java:431 fails.

Common situations: Building parameterized tokens from user-driven Class objects where the caller can pass anything; refactoring a generic class to add a bound and forgetting to update callers; using libraries that constrain type parameters heavily (e.g. enums, Comparable).

Related errors


AI-assisted analysis of google/gson@8b8628c656 (2026-08-04). Data as JSON: /data/errors/04348b5807ea6f85.json. Report an issue: GitHub.