google/gson · error · IllegalStateException

TypeToken must be created with a type argument: new…

Error message

TypeToken must be created with a type argument: new TypeToken<...>() {}; When using code shrinkers (ProGuard, R8, ...) make sure that generic signatures are preserved.
See {}

What it means

Thrown by TypeToken's protected constructor when the anonymous subclass's generic superclass is the RAW TypeToken class (no type argument supplied) rather than ParameterizedType<TypeToken<...>>. Gson cannot recover the missing type argument. The message explicitly calls out code shrinkers (ProGuard/R8) that strip generic signatures as a common cause.

Solutions

  1. If using ProGuard/R8, add `-keepattributes Signature` (and typically `*Annotation*`, `InnerClasses`) to your rules; for R8 this is usually inherited from the default Android rules but verify.
  2. Ensure TypeToken is instantiated as an anonymous subclass with an explicit type argument: `new TypeToken<List<String>>() {}` (note the empty `{}`).
  3. If a type argument is only known at runtime, use TypeToken.getParameterized(...) instead of an anonymous subclass.
  4. Update Gson and the Android Gradle Plugin; old AGP/Gson combinations occasionally drop signatures.

Example fix

// before (broken)
TypeToken<?> t = new TypeToken(){}; // raw, no type argument
// or ProGuard stripped signature from:
TypeToken<List<String>> t = new TypeToken<List<String>>(){};

// after (code fix)
TypeToken<List<String>> t = new TypeToken<List<String>>() {};

// after (ProGuard fix in proguard-rules.pro):
-keepattributes Signature, InnerClasses, EnclosingMethod
-keep class com.google.gson.reflect.TypeToken
-keep class * extends com.google.gson.reflect.TypeToken

// after (runtime-known type):
TypeToken<?> t = TypeToken.getParameterized(List.class, String.class);
Defensive patterns

Strategy: validation

Validate before calling

// at app startup, verify generic signatures survive shrinking
TypeToken<List<String>> t = new TypeToken<List<String>>() {};
if (t.getType() instanceof Class) { // raw TypeToken, signature stripped
  throw new IllegalStateException("Generic signatures stripped; add -keepattributes Signature");
}

Type guard

public static boolean typeTokenResolved(TypeToken<?> t) {
  return !(t.getType() instanceof Class) || ((Class<?>) t.getType()).getTypeParameters().length == 0 && t.getType() != TypeToken.class;
}

Try / catch

try {
  TypeToken<List<String>> t = new TypeToken<List<String>>() {};
  return gson.fromJson(json, t.getType());
} catch (IllegalStateException e) {
  if (e.getMessage().startsWith("TypeToken must be created with a type argument")) {
    throw new IllegalStateException("ProGuard/R8 stripped signatures; add -keepattributes Signature", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: Writing `new TypeToken(){}` (no <...>), or a properly-written `new TypeToken<List<String>>(){}` whose generic signature was stripped at build time by ProGuard/R8 without -keepattributes Signature. Also possible when reflection over the class file does not return ParameterizedType due to compiler bugs.

Common situations: Android release builds with ProGuard/R8 missing Signature attribute retention; copying TypeToken usage without the empty anonymous-class body or without the type argument; obfuscation configs that strip Signature/InnerClasses; some older Android Gradle Plugin defaults.

Related errors


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

Appendix: source

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

   * Verifies that {@code this} is an instance of a direct subclass of TypeToken and returns the
   * type argument for {@code T} in {@link GsonTypes#canonicalize canonical form}.
   */
  private Type getTypeTokenTypeArgument() {
    Type superclass = getClass().getGenericSuperclass();
    if (superclass instanceof ParameterizedType) {
      ParameterizedType parameterized = (ParameterizedType) superclass;
      if (parameterized.getRawType() == TypeToken.class) {
        Type typeArgument = GsonTypes.canonicalize(parameterized.getActualTypeArguments()[0]);

        if (isCapturingTypeVariablesForbidden()) {
          verifyNoTypeVariable(typeArgument);
        }
        return typeArgument;
      }
    }
    // Check for raw TypeToken as superclass
    else if (superclass == TypeToken.class) {
      throw new IllegalStateException(
          "TypeToken must be created with a type argument: new TypeToken<...>() {}; When using code"
              + " shrinkers (ProGuard, R8, ...) make sure that generic signatures are preserved."
              + "\nSee "
              + TroubleshootingGuide.createUrl("type-token-raw"));
    }

    // User created subclass of subclass of TypeToken
    throw new IllegalStateException("Must only create direct subclasses of TypeToken");
  }

  private static void verifyNoTypeVariable(Type type) {
    if (type instanceof TypeVariable) {
      TypeVariable<?> typeVariable = (TypeVariable<?>) type;
      throw new IllegalArgumentException(
          "TypeToken type argument must not contain a type variable; captured type variable "
              + typeVariable.getName()
              + " declared by "
              + typeVariable.getGenericDeclaration()

View on GitHub (pinned to 310ac341f2)