google/gson · error · JsonIOException

Invalid EnumSet type: {type}

Error message

Invalid EnumSet type: {type}

What it means

ConstructorConstructor builds an EnumSet factory only when the type is a ParameterizedType whose first type argument is a Class (the enum element type). If the argument is a ParameterizedType, TypeVariable, WildcardType, etc., it throws JsonIOException with the offending type.

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 8b8628c656)

Solutions

  1. Declare the field as EnumSet<MyEnum> with a concrete enum class.
  2. Build a TypeToken with the concrete enum: new TypeToken<EnumSet<MyEnum>>(){}.
  3. Register an InstanceCreator<EnumSet> that supplies EnumSet.noneOf(MyEnum.class).
  4. Avoid wildcards/type variables on EnumSet fields used for deserialization.

Example fix

// before
EnumSet<? extends Color> colors; // fails

// after
EnumSet<Color> colors; // concrete enum type
Defensive patterns

Strategy: validation

Validate before calling

if (type instanceof ParameterizedType
    && ((ParameterizedType) type).getActualTypeArguments()[0] instanceof Class) {
  // safe to let Gson construct EnumSet
}

Type guard

boolean isConcreteEnumSetType(Type t) {
  return t instanceof ParameterizedType
      && ((ParameterizedType) t).getActualTypeArguments()[0] instanceof Class;
}

Try / catch

try {
  return gson.fromJson(json, type);
} catch (JsonIOException ex) {
  if (ex.getMessage().startsWith("Invalid EnumSet type")) {
    // register InstanceCreator and retry with EnumSet.noneOf(MyEnum.class)
  }
  throw ex;
}

Prevention

When it happens

Trigger: Deserializing a field declared as EnumSet<? extends MyEnum>, EnumSet<T> with a type variable, or EnumSet with a parameterized element type; reflective construction from generic TypeTokens that lose the concrete enum class.

Common situations: Generic utility classes holding EnumSet<E>; wildcard bounds in API models; incorrectly built TypeToken<EnumSet<...>> where the enum type is erased at capture.

Related errors


AI-assisted analysis of google/gson@8b8628c656 (2026-08-04). Data as JSON: /data/errors/9f452bb2c5f9a061.json. Report an issue: GitHub.