google/gson · error · JsonIOException

Invalid EnumSet type

Error message

Invalid EnumSet type: ${type}

What it means

Thrown when Gson constructs an EnumSet whose declared type is a ParameterizedType but the element type argument is not a concrete Class (e.g. a TypeVariable or WildcardType). EnumSet.noneOf() requires a concrete enum class, so Gson cannot proceed. The message includes the unresolved type.

Solutions

  1. Use a concrete TypeToken<EnumSet<MyEnum>> when calling fromJson so the element type is a Class
  2. Register an InstanceCreator<EnumSet> that returns EnumSet.noneOf(MyEnum.class)
  3. Register a TypeAdapter for the generic wrapper type that resolves the enum concretely

Example fix

// before - E is unresolved
class Wrapper<E extends Enum<E>> { EnumSet<E> values; }
gson.fromJson(json, new TypeToken<Wrapper<MyEnum>>(){}.getType());

// after - register InstanceCreator
gsonBuilder.registerTypeAdapter(EnumSet.class,
  (InstanceCreator<EnumSet>) type -> EnumSet.noneOf(MyEnum.class));
Defensive patterns

Strategy: type-guard

Validate before calling

// Ensure EnumSet element type is a concrete Class before deserializing
Type targetType = typeToken.getType();
if (targetType instanceof ParameterizedType) {
  Type arg0 = ((ParameterizedType) targetType).getActualTypeArguments()[0];
  if (!(arg0 instanceof Class)) {
    throw new IllegalStateException("EnumSet element type must be concrete Class, got " + arg0);
  }
}

Type guard

static boolean isConcreteEnumSet(Type type) {
  if (!(type instanceof ParameterizedType)) return false;
  ParameterizedType pt = (ParameterizedType) type;
  if (!EnumSet.class.isAssignableFrom((Class<?>) pt.getRawType())) return false;
  return pt.getActualTypeArguments()[0] instanceof Class
      && ((Class<?>) pt.getActualTypeArguments()[0]).isEnum();
}

Prevention

When it happens

Trigger: Deserializing a generic type like EnumSet<T> where T is an unresolved type variable at deserialization time; a generic wrapper class with an EnumSet<E> field where E cannot be resolved to a concrete enum.

Common situations: Generic container classes holding EnumSet<E> fields deserialized without a concrete type binding; subclassing generic types without reifying the type parameter.

Related errors


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

Appendix: source

Thrown at gson/src/main/java/com/google/gson/internal/ConstructorConstructor.java:188

    return newUnsafeAllocator(rawType);
  }

  /**
   * Creates constructors for special JDK collection types which do not have a public no-args
   * constructor.
   */
  private static <T> ObjectConstructor<T> newSpecialCollectionConstructor(
      Type type, Class<? super T> rawType) {
    if (EnumSet.class.isAssignableFrom(rawType)) {
      return () -> {
        if (type instanceof ParameterizedType) {
          Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];
          if (elementType instanceof Class) {
            @SuppressWarnings({"unchecked", "rawtypes"})
            T set = (T) EnumSet.noneOf((Class) elementType);
            return set;
          } else {
            throw new JsonIOException("Invalid EnumSet type: " + type);
          }
        } else {
          throw new JsonIOException("Invalid EnumSet type: " + type);
        }
      };
    }
    // Only support creation of EnumMap, but not of custom subtypes; for them type parameters
    // and constructor parameter might have completely different meaning
    else if (rawType == EnumMap.class) {
      return () -> {
        if (type instanceof ParameterizedType) {
          Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];
          if (elementType instanceof Class) {
            @SuppressWarnings({"unchecked", "rawtypes"})
            T map = (T) new EnumMap((Class) elementType);
            return map;
          } else {
            throw new JsonIOException("Invalid EnumMap type: " + type);

View on GitHub (pinned to 310ac341f2)