{"record":{"id":"481e0800b6fd9974","repo":"google/gson","slug":"at-most-one-lower-bound-is-supported","errorCode":null,"errorMessage":"At most one lower bound is supported","messagePattern":"At most one lower bound is supported","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/internal/GsonTypes.java","lineNumber":627,"sourceCode":"    public String toString() {\n      return typeToString(componentType) + \"[]\";\n    }\n  }\n\n  /**\n   * The WildcardType interface supports multiple upper bounds and multiple lower bounds. We only\n   * support what the target Java version supports - at most one bound, see also\n   * https://bugs.openjdk.java.net/browse/JDK-8250660. If a lower bound is set, the upper bound must\n   * be Object.class.\n   */\n  private static final class WildcardTypeImpl implements WildcardType {\n    private final Type upperBound;\n\n    private final Type lowerBound;\n\n    WildcardTypeImpl(Type[] upperBounds, Type[] lowerBounds) {\n      if (lowerBounds.length > 1) {\n        throw new IllegalArgumentException(\"At most one lower bound is supported\");\n      }\n      if (upperBounds.length != 1) {\n        throw new IllegalArgumentException(\"Exactly one upper bound must be specified\");\n      }\n\n      if (lowerBounds.length == 1) {\n        requireNonNull(lowerBounds[0]);\n        checkNotPrimitive(lowerBounds[0]);\n        if (upperBounds[0] != Object.class) {\n          throw new IllegalArgumentException(\n              \"When lower bound is specified, upper bound must be Object\");\n        }\n        this.lowerBound = canonicalize(lowerBounds[0]);\n        this.upperBound = Object.class;\n\n      } else {\n        requireNonNull(upperBounds[0]);\n        checkNotPrimitive(upperBounds[0]);","sourceCodeStart":609,"sourceCodeEnd":645,"githubUrl":"https://github.com/google/gson/blob/310ac341f2f92a454b229bf21f70d2d18b2b6db7/gson/src/main/java/com/google/gson/internal/GsonTypes.java#L609-L645","documentation":"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).","triggerScenarios":"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.","commonSituations":"Custom TypeAdapterFactory code that programmatically builds wildcard types; migrating from libraries that expose getLowerBounds() arrays verbatim; test fixtures that synthesize malformed wildcards.","solutions":["Pass exactly one lower bound (or none) when constructing the wildcard; combine multiple candidate bounds into a single common supertype first.","If you are aggregating bounds, intersect them at the upper bound instead and use an upper-bounded wildcard.","Avoid building WildcardType manually; prefer TypeToken/TypeToken.getParameterized which produce correct wildcards."],"exampleFix":"// before\nnew WildcardTypeImpl(new Type[]{Object.class}, new Type[]{String.class, Number.class});\n// after\nnew WildcardTypeImpl(new Type[]{Object.class}, new Type[]{String.class});","handlingStrategy":"validation","validationCode":"if (lowerBounds != null && lowerBounds.length > 1) throw new IllegalArgumentException(\"only one lower bound allowed\");","typeGuard":"static boolean singleLowerBound(Type[] lbs) { return lbs == null || lbs.length <= 1; }","tryCatchPattern":null,"preventionTips":["Do not construct WildcardType manually; prefer TypeToken.","When aggregating bounds from multiple sources, intersect to a single common supertype first.","Add a unit test that builds every wildcard your code constructs and asserts at most one lower bound."],"tags":["gson","reflection","generics","wildcard"],"backgroundTag":null,"analyzedSha":"310ac341f2f92a454b229bf21f70d2d18b2b6db7","analyzedAt":"2026-08-10T02:58:47.455Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}