{"record":{"id":"a85063cdfa813b6e","repo":"google/gson","slug":"when-lower-bound-is-specified-upper-bound-must-be","errorCode":null,"errorMessage":"When lower bound is specified, upper bound must be Object","messagePattern":"When lower bound is specified, upper bound must be Object","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/internal/GsonTypes.java","lineNumber":637,"sourceCode":"   */\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]);\n        this.lowerBound = null;\n        this.upperBound = canonicalize(upperBounds[0]);\n      }\n    }\n\n    @Override\n    public Type[] getUpperBounds() {\n      return new Type[] {upperBound};\n    }\n","sourceCodeStart":619,"sourceCodeEnd":655,"githubUrl":"https://github.com/google/gson/blob/310ac341f2f92a454b229bf21f70d2d18b2b6db7/gson/src/main/java/com/google/gson/internal/GsonTypes.java#L619-L655","documentation":"Thrown by WildcardTypeImpl when a lower bound is supplied but the upper bound is not exactly Object.class. A wildcard is either upper-bounded (<? extends T>, upper != Object, lower == none) or lower-bounded (<? super T>, upper == Object, lower == T); mixing both is meaningless in Java source. Gson enforces the invariant at GsonTypes.java:636.","triggerScenarios":"Constructing a WildcardTypeImpl with both a non-Object upper bound and a lower bound, e.g. new WildcardTypeImpl(new Type[]{Number.class}, new Type[]{String.class}).","commonSituations":"Programmatic Type builders that fill both arrays from a generic descriptor; bridging code that mirrors annotation/type-use metadata containing both bounds; malformed test fixtures.","solutions":["Decide which form you mean: upper-bounded (only upperBounds set, lower empty) or lower-bounded (upper = Object.class, lower set).","Drop the lower bound if you really want an upper-bounded wildcard, or set upper to Object.class if you really want a lower-bounded wildcard.","Do not synthesize bounds from arbitrary type metadata without normalizing to one of the two legal wildcard shapes."],"exampleFix":"// before (ambiguous; throws)\nnew WildcardTypeImpl(new Type[]{Number.class}, new Type[]{String.class});\n// after (lower-bounded)\nnew WildcardTypeImpl(new Type[]{Object.class}, new Type[]{String.class});","handlingStrategy":"validation","validationCode":"boolean validWildcard(Type[] up, Type[] lo) {\n  if (lo != null && lo.length == 1) {\n    return up != null && up.length == 1 && up[0] == Object.class;\n  }\n  return true;\n}","typeGuard":"static boolean isLegalWildcard(Type[] up, Type[] lo) {\n  return (lo == null || lo.length == 0) || (up != null && up.length == 1 && up[0] == Object.class);\n}","tryCatchPattern":null,"preventionTips":["Remember: a wildcard is either upper-bounded or lower-bounded, never both meaningfully.","Reject type metadata containing both bounds at the bridge boundary rather than forwarding it."],"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"}