{"record":{"id":"31fb5dce4229bafa","repo":"baomidou/mybatis-plus","slug":"type-argument-must-be-an-enum","errorCode":null,"errorMessage":"Type argument must be an enum: {}","messagePattern":"Type argument must be an enum: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/EnumCache.java","lineNumber":73,"sourceCode":"        }\n        return CACHE.computeIfAbsent(enumClassType, EnumCache::createMetadata);\n    }\n\n    static Optional<String> findEnumValueFieldName(Class<?> clazz) {\n        if (clazz == null || !clazz.isEnum()) {\n            return Optional.empty();\n        }\n        String fieldName = ENUM_VALUE_FIELD_CACHE.computeIfAbsent(clazz, EnumCache::findEnumValueFieldNameOrEmpty);\n        return NO_ENUM_VALUE_FIELD.equals(fieldName) ? Optional.empty() : Optional.of(fieldName);\n    }\n\n    static boolean isMpEnums(Class<?> clazz) {\n        return clazz != null && clazz.isEnum() && (IEnum.class.isAssignableFrom(clazz) || findEnumValueFieldName(clazz).isPresent());\n    }\n\n    private static EnumMetadata createMetadata(Class<?> enumClassType) {\n        if (!enumClassType.isEnum()) {\n            throw new IllegalArgumentException(\"Type argument must be an enum: \" + enumClassType.getName());\n        }\n        MetaClass metaClass = MetaClass.forClass(enumClassType, REFLECTOR_FACTORY);\n        String getterName = resolveGetterName(enumClassType);\n        Class<?> propertyType = ReflectionKit.resolvePrimitiveIfNecessary(metaClass.getGetterType(getterName));\n        Invoker getInvoker = metaClass.getGetInvoker(getterName);\n        Enum<?>[] enumConstants = (Enum<?>[]) enumClassType.getEnumConstants();\n        Map<Object, Enum<?>> valueToEnum = new HashMap<>(enumConstants.length * 4 + 1);\n        Map<Enum<?>, Object> enumToValue = new IdentityHashMap<>(enumConstants.length);\n        for (Enum<?> enumConstant : enumConstants) {\n            Object value = invokeValue(getInvoker, enumConstant);\n            enumToValue.put(enumConstant, value);\n            EnumUtils.putEnumValue(valueToEnum, value, enumConstant);\n        }\n        return new EnumMetadata(propertyType, enumConstants, Collections.unmodifiableMap(valueToEnum),\n            Collections.unmodifiableMap(enumToValue), getterName);\n    }\n\n    private static String resolveGetterName(Class<?> enumClassType) {","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/baomidou/mybatis-plus/blob/bf67d907478c724120bf76292da54abf9e73c2b3/mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/EnumCache.java#L55-L91","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: class implements IEnum but is not an enum -> IAE\npublic class Status implements IEnum<Integer> { ... }\n\n// after: declare it as an enum\npublic enum Status implements IEnum<Integer> {\n    OK(0), FAIL(1);\n    private final int code;\n    Status(int code) { this.code = code; }\n    public Integer getValue() { return code; }\n}","handlingStrategy":"type-guard","validationCode":"if (!clazz.isEnum()) {\n    throw new IllegalArgumentException(clazz + \" is not an enum; enum handling requires java.lang.Enum\");\n}","typeGuard":"static boolean isMpEnum(Class<?> c) {\n    return c != null && c.isEnum()\n        && (IEnum.class.isAssignableFrom(c) || EnumCache.findEnumValueFieldName(c).isPresent());\n}","tryCatchPattern":"try {\n    EnumCache.metadata(candidate);\n} catch (IllegalArgumentException e) {\n    // fall back to non-enum handling instead of failing\n    handleAsNonEnum(candidate);\n}","preventionTips":["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."],"tags":["enum","type-handler","argument-validation"],"backgroundTag":null,"analyzedSha":"bf67d907478c724120bf76292da54abf9e73c2b3","analyzedAt":"2026-08-14T15:17:09.543Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}