google/gson · error · IllegalArgumentException
rawType must be of type Class, but was {}
Error message
rawType must be of type Class, but was {} What it means
Thrown by TypeToken.getParameterized when the rawType argument is not an instance of java.lang.Class (e.g. a ParameterizedType, GenericArrayType, TypeVariable, or WildcardType). getParameterized validates rawType explicitly because it is the only public API where users can construct malformed parameterized types; JDK bug JDK-8250659 is referenced.
Source
Thrown at gson/src/main/java/com/google/gson/reflect/TypeToken.java:393
*
* As seen here the result is a {@code TypeToken<?>}; this method cannot provide any type-safety,
* and care must be taken to pass in the correct number of type arguments.
*
* <p>If {@code rawType} is a non-generic class and no type arguments are provided, this method
* simply delegates to {@link #get(Class)} and creates a {@code TypeToken(Class)}.
*
* @throws IllegalArgumentException If {@code rawType} is not of type {@code Class}, or if the
* type arguments are invalid for the raw type
*/
public static TypeToken<?> getParameterized(Type rawType, Type... typeArguments) {
Objects.requireNonNull(rawType);
Objects.requireNonNull(typeArguments);
// Perform basic validation here because this is the only public API where users
// can create malformed parameterized types
if (!(rawType instanceof Class)) {
// See also https://bugs.openjdk.org/browse/JDK-8250659
throw new IllegalArgumentException("rawType must be of type Class, but was " + rawType);
}
Class<?> rawClass = (Class<?>) rawType;
TypeVariable<?>[] typeVariables = rawClass.getTypeParameters();
int expectedArgsCount = typeVariables.length;
int actualArgsCount = typeArguments.length;
if (actualArgsCount != expectedArgsCount) {
throw new IllegalArgumentException(
rawClass.getName()
+ " requires "
+ expectedArgsCount
+ " type arguments, but got "
+ actualArgsCount);
}
// For legacy reasons create a TypeToken(Class) if the type is not generic
if (typeArguments.length == 0) {
return get(rawClass);View on GitHub (pinned to 310ac341f2)
Solutions
- Pass the raw Class (e.g. Map.class, List.class), not a parameterized Type. If you have a Type, get its erasure via GsonTypes.getRawType or Class.forName first.
- For nested generics, build from the inside out with getParameterized and pass the result's getType() only as a type argument, never as rawType.
- If you already hold a Type, use TypeToken.get(type) instead of getParameterized.
- Add a runtime assertion `assert rawType instanceof Class` before calling to fail fast in tests.
Example fix
// before (broken)
Type listType = new TypeToken<List<String>>(){}.getType();
TypeToken<?> t = TypeToken.getParameterized(listType, String.class); // listType not a Class -> throws
// after: pass the raw Class
TypeToken<?> t = TypeToken.getParameterized(List.class, String.class);
// or, if you already have a Type, use TypeToken.get:
TypeToken<?> t = TypeToken.get(listType);
// for Map<String, List<Integer>>:
TypeToken<?> inner = TypeToken.getParameterized(List.class, Integer.class);
TypeToken<?> outer = TypeToken.getParameterized(Map.class, String.class, inner.getType()); Defensive patterns
Strategy: validation
Validate before calling
// guard before calling getParameterized
if (!(rawType instanceof Class)) {
// either resolve erasure, or use TypeToken.get(rawType)
rawType = rawType instanceof ParameterizedType
? ((ParameterizedType) rawType).getRawType()
: rawType;
}
if (!(rawType instanceof Class)) {
throw new IllegalArgumentException("rawType must be Class, got: " + rawType);
} Type guard
public static boolean isRawClass(Type t) {
return t instanceof Class;
} Try / catch
try {
return TypeToken.getParameterized(rawType, args);
} catch (IllegalArgumentException e) {
if (e.getMessage().startsWith("rawType must be of type Class")) {
// fall back: if it's already a resolved Type, use TypeToken.get
return TypeToken.get(rawType);
}
throw e;
} Prevention
- Always pass a Class as the first argument to getParameterized.
- If you already have a Type, use TypeToken.get(type).
- Build nested generics inside-out, passing inner getType() as a type argument only.
- Add an `assert rawType instanceof Class` in test code to fail fast.
When it happens
Trigger: Calling TypeToken.getParameterized(someType, ...) where someType is itself a parameterized type (like List<String>.class equivalent) or a GenericArrayType, rather than a plain Class. Example: TypeToken.getParameterized(new TypeToken<List<String>>(){}.getType(), String.class) passes a ParameterizedType as rawType.
Common situations: Mistakenly passing a Type's toString or a nested generic type where the raw class is expected; chained calls that hand a resolved generic type instead of the erasure; copying patterns from getParameterized examples and feeding the wrong slot; confusion between raw type and parameterized type.
Related errors
- TypeToken type argument must not contain a type variable; ca
- TypeToken captured `null` as type argument; probably a compi
- Primitive type is not allowed
- Must specify owner type for ${rawType}
- TypeToken must be created with a type argument: new TypeToke
AI-assisted analysis of google/gson@310ac341f2 (2026-08-10).
Data as JSON: /api/errors/8364825de424d404.
Report an issue: GitHub.