baomidou/mybatis-plus · error · IllegalArgumentException
Type argument must be an enum: {}
Error message
Type argument must be an enum: {} What it means
EnumCache.createMetadata builds the EnumMetadata (value-to-enum mappings) for a class and throws IllegalArgumentException('Type argument must be an enum: X') when the class is not java.lang.Enum. The metadata cache is only valid for enums; passing an interface, annotation, or ordinary class means value extraction (getEnumConstants, IEnum interface check) cannot proceed.
Source
Thrown at mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/EnumCache.java:73
}
return CACHE.computeIfAbsent(enumClassType, EnumCache::createMetadata);
}
static Optional<String> findEnumValueFieldName(Class<?> clazz) {
if (clazz == null || !clazz.isEnum()) {
return Optional.empty();
}
String fieldName = ENUM_VALUE_FIELD_CACHE.computeIfAbsent(clazz, EnumCache::findEnumValueFieldNameOrEmpty);
return NO_ENUM_VALUE_FIELD.equals(fieldName) ? Optional.empty() : Optional.of(fieldName);
}
static boolean isMpEnums(Class<?> clazz) {
return clazz != null && clazz.isEnum() && (IEnum.class.isAssignableFrom(clazz) || findEnumValueFieldName(clazz).isPresent());
}
private static EnumMetadata createMetadata(Class<?> enumClassType) {
if (!enumClassType.isEnum()) {
throw new IllegalArgumentException("Type argument must be an enum: " + enumClassType.getName());
}
MetaClass metaClass = MetaClass.forClass(enumClassType, REFLECTOR_FACTORY);
String getterName = resolveGetterName(enumClassType);
Class<?> propertyType = ReflectionKit.resolvePrimitiveIfNecessary(metaClass.getGetterType(getterName));
Invoker getInvoker = metaClass.getGetInvoker(getterName);
Enum<?>[] enumConstants = (Enum<?>[]) enumClassType.getEnumConstants();
Map<Object, Enum<?>> valueToEnum = new HashMap<>(enumConstants.length * 4 + 1);
Map<Enum<?>, Object> enumToValue = new IdentityHashMap<>(enumConstants.length);
for (Enum<?> enumConstant : enumConstants) {
Object value = invokeValue(getInvoker, enumConstant);
enumToValue.put(enumConstant, value);
EnumUtils.putEnumValue(valueToEnum, value, enumConstant);
}
return new EnumMetadata(propertyType, enumConstants, Collections.unmodifiableMap(valueToEnum),
Collections.unmodifiableMap(enumToValue), getterName);
}
private static String resolveGetterName(Class<?> enumClassType) {View on GitHub (pinned to bf67d90747)
Solutions
- Make the mapped type an actual enum (declare it with the enum keyword) — classes merely implementing IEnum are not supported.
- Check the registered type handler for the field: non-enum types must not be handled by the enum type handler chain.
- Guard call sites with clazz.isEnum() (or EnumCache.isMpEnums(clazz)) before touching enum metadata APIs.
Example fix
// before: class implements IEnum but is not an enum -> IAE
public class Status implements IEnum<Integer> { ... }
// after: declare it as an enum
public enum Status implements IEnum<Integer> {
OK(0), FAIL(1);
private final int code;
Status(int code) { this.code = code; }
public Integer getValue() { return code; }
} Defensive patterns
Strategy: type-guard
Validate before calling
if (!clazz.isEnum()) {
throw new IllegalArgumentException(clazz + " is not an enum; enum handling requires java.lang.Enum");
} Type guard
static boolean isMpEnum(Class<?> c) {
return c != null && c.isEnum()
&& (IEnum.class.isAssignableFrom(c) || EnumCache.findEnumValueFieldName(c).isPresent());
} Try / catch
try {
EnumCache.metadata(candidate);
} catch (IllegalArgumentException e) {
// fall back to non-enum handling instead of failing
handleAsNonEnum(candidate);
} Prevention
- Guard every reflective entry into enum machinery with clazz.isEnum().
- Never implement IEnum on a non-enum class; review enum contracts when adding type handlers.
When it happens
Trigger: Cache.computeIfAbsent(enumClassType, EnumCache::createMetadata) runs with a non-enum class — e.g. code path determined a field 'is an mp enum' incorrectly, or a custom type handler invoked EnumCache lookups on a plain class. Also reachable when an enum-like class (abstract class implementing IEnum without being an enum) is routed to the enum cache.
Common situations: A class implements IEnum but is not declared as enum; the wrong type handler is registered for a field so enum machinery runs against a normal class; reflective code feeds raw Class objects into enum caching utilities.
Related errors
- Type argument cannot be null
- Type argument cannot be null
- Failed invoking constructor for handler %s
- Unable to find a usable constructor for %s
- Type argument cannot be null
AI-assisted analysis of baomidou/mybatis-plus@bf67d90747 (2026-08-14).
Data as JSON: /api/errors/31fb5dce4229bafa.
Report an issue: GitHub.