google/gson · error · IllegalArgumentException

TypeToken captured `null` as type argument; probably a…

Error message

TypeToken captured `null` as type argument; probably a compiler / runtime bug

What it means

Thrown by TypeToken.verifyNoTypeVariable when a component of the captured type argument is null. This is a known JDK/Eclipse compiler quirk (see eclipse-jdt/eclipse.jdt.core#975, reproduced e.g. on Java 11.0.18) where capturing a type variable declared by a method of a local class yields null instead of a TypeVariable. The message explicitly attributes it to a compiler/runtime bug.

Solutions

  1. Build with javac instead of Eclipse ecj (or update Eclipse JDT to a version with the fix for eclipse.jdt.core#975).
  2. Update to a JDK point release that no longer exhibits the null-returning reflection bug.
  3. Refactor to avoid TypeToken capture inside local classes with generic methods; use TypeToken.getParameterized at runtime instead.
  4. If unavoidable, the system property gson.allowCapturingTypeVariables=true bypasses verifyNoTypeVariable entirely (accept the type-safety implications).

Example fix

// before (broken on affected Eclipse/JDK)
public void process() {
  class Local {
    <T> TypeToken<T> token() { return new TypeToken<T>() {}; } // null type var on buggy JVM
  }
}

// after: avoid capture; use runtime construction
public void process(Class<?> type) {
  TypeToken<?> token = TypeToken.get(type);
}

// build with javac instead of ecj, or update Eclipse JDT/JDK to a fixed release.
Defensive patterns

Strategy: fallback

Validate before calling

// detect affected toolchain early; recommend build-system switch
System.out.println("javac/ecj: " + System.getProperty("java.vm.version"));
// prefer building with javac; in tests assert a known TypeToken resolves
TypeToken<?> probe = TypeToken.get(String.class);
if (probe == null) throw new IllegalStateException();

Try / catch

try {
  return new TypeToken<T>() {}; // local class generic method on buggy JVM
} catch (IllegalArgumentException e) {
  if (e.getMessage().startsWith("TypeToken captured `null`")) {
    // bypass verify by constructing at runtime
    return TypeToken.get(elementType);
  }
  throw e;
}

Prevention

When it happens

Trigger: Using the Eclipse JDT compiler (or an affected JDK like 11.0.18) and constructing a TypeToken inside a local class whose method declares a type variable that gets captured. The reflection API returns null where a TypeVariable was expected, tripping the `type == null` branch.

Common situations: Eclipse IDE builds producing class files that exhibit the null type-variable bug; specific JDK point releases (11.0.18) with the underlying reflection bug; local/anonymous classes with generic methods; switching between javac and ecj producing different runtime behavior.

Related errors


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

Appendix: source

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

        verifyNoTypeVariable(ownerType);
      }

      for (Type typeArgument : parameterizedType.getActualTypeArguments()) {
        verifyNoTypeVariable(typeArgument);
      }
    } else if (type instanceof WildcardType) {
      WildcardType wildcardType = (WildcardType) type;
      for (Type bound : wildcardType.getLowerBounds()) {
        verifyNoTypeVariable(bound);
      }
      for (Type bound : wildcardType.getUpperBounds()) {
        verifyNoTypeVariable(bound);
      }
    } else if (type == null) {
      // Occurs in Eclipse IDE and certain Java versions (e.g. Java 11.0.18) when capturing type
      // variable declared by method of local class, see
      // https://github.com/eclipse-jdt/eclipse.jdt.core/issues/975
      throw new IllegalArgumentException(
          "TypeToken captured `null` as type argument; probably a compiler / runtime bug");
    }
  }

  /** Returns the raw (non-generic) type for this type. */
  public final Class<? super T> getRawType() {
    return rawType;
  }

  /** Gets underlying {@code Type} instance. */
  public final Type getType() {
    return type;
  }

  /**
   * Check if this type is assignable from the given class object.
   *
   * @deprecated this implementation may be inconsistent with javac for types with wildcards.

View on GitHub (pinned to 310ac341f2)