{"record":{"id":"c2ab775631ba596e","repo":"mybatis/mybatis-3","slug":"failed-to-invoke-constructor","errorCode":null,"errorMessage":"Failed to invoke constructor {}","messagePattern":"Failed to invoke constructor (.+?)","errorType":"exception","errorClass":"TypeException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/type/TypeHandlerRegistry.java","lineNumber":328,"sourceCode":"    if (candidate == null) {\n      if (type instanceof Class) {\n        Class<?> clazz = (Class<?>) type;\n        if (Enum.class.isAssignableFrom(clazz)) {\n          Class<?> enumClass = (clazz.isAnonymousClass() || !clazz.isEnum()) ? clazz.getSuperclass() : clazz;\n          TypeHandler<?> enumHandler = getInstance(enumClass, defaultEnumTypeHandler);\n          register(new Type[] { enumClass }, new JdbcType[] { jdbcType }, enumHandler);\n          return enumHandler;\n        }\n      }\n      return null;\n    }\n\n    try {\n      TypeHandler<?> typeHandler = (TypeHandler<?>) candidate.newInstance(type);\n      register(type, jdbcType, typeHandler);\n      return typeHandler;\n    } catch (ReflectiveOperationException e) {\n      throw new TypeException(\"Failed to invoke constructor \" + candidate.toString(), e);\n    }\n  }\n\n  private Map<JdbcType, TypeHandler<?>> getJdbcHandlerMap(Type type) {\n    Map<JdbcType, TypeHandler<?>> jdbcHandlerMap = typeHandlerMap.get(type);\n    if (jdbcHandlerMap != null) {\n      return NULL_TYPE_HANDLER_MAP.equals(jdbcHandlerMap) ? null : jdbcHandlerMap;\n    }\n    if (type instanceof Class) {\n      Class<?> clazz = (Class<?>) type;\n      if (!Enum.class.isAssignableFrom(clazz)) {\n        jdbcHandlerMap = getJdbcHandlerMapForSuperclass(clazz);\n      }\n    }\n    typeHandlerMap.put(type, jdbcHandlerMap == null ? NULL_TYPE_HANDLER_MAP : jdbcHandlerMap);\n    return jdbcHandlerMap;\n  }\n","sourceCodeStart":310,"sourceCodeEnd":346,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/type/TypeHandlerRegistry.java#L310-L346","documentation":"When a type handler is instantiated on demand, TypeHandlerRegistry calls candidate.newInstance(type) through reflection. Any ReflectiveOperationException — including an exception thrown INSIDE the constructor, such as EnumTypeHandler's 'Type argument cannot be null' — surfaces as this TypeException naming the handler class.","triggerScenarios":"A custom or built-in handler whose Class-arg constructor throws (null java type passed by the registry, unsupported type argument); a handler class with a non-public constructor (IllegalAccessException surfaces here too).","commonSituations":"Custom handlers that validate their constructor argument and throw for null; registering a handler class whose only constructor is package-private; handler constructors that perform external lookups (JNDI, service) that fail at init.","solutions":["Read the cause: if it is another exception, the constructor itself threw — fix that root cause (usually a null/unresolvable java type)","Give the handler class a public no-arg constructor and a public constructor taking Class","Register the handler with an explicit javaType so the registry never passes null"],"exampleFix":"// before\nclass MyHandler extends BaseTypeHandler<MyType> {\n  public MyHandler(Class<?> type) { if (type == null) throw new IllegalStateException(); }\n}\n\n// after\nclass MyHandler extends BaseTypeHandler<MyType> {\n  public MyHandler() {}\n  public MyHandler(Class<?> type) { /* tolerate null, default sensibly */ }\n}","handlingStrategy":"try-catch","validationCode":"// verify a usable constructor exists before registering\nboolean usable = Arrays.stream(handlerClass.getConstructors())\n  .anyMatch(c -> c.getParameterCount() == 1 && (Type.class.equals(c.getParameterTypes()[0]) || Class.class.equals(c.getParameterTypes()[0])));\nif (!usable && Arrays.stream(handlerClass.getConstructors()).noneMatch(c -> c.getParameterCount() == 0)) {\n  throw new IllegalStateException(handlerClass + \" has no (Class) or () constructor\");\n}","typeGuard":null,"tryCatchPattern":"try { registry.getInstance(type, handlerClass); } catch (TypeException e) { // unwrap cause; if constructor logic threw, fix the constructor rather than retrying }","preventionTips":["Keep handler constructors side-effect free and null-tolerant","Give every custom handler a public no-arg constructor","Instantiate handlers once in tests to surface constructor problems before production"],"tags":["mybatis","type-handler","reflection","registration"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}