mybatis/mybatis-3 · error · BuilderException

Type {typeHandlerType} is not a valid TypeHandler because it

Error message

Type {typeHandlerType} is not a valid TypeHandler because it does not implement TypeHandler interface

What it means

When a typeHandler alias is resolved from configuration (XML attribute or annotation string), BaseBuilder verifies the resulting class actually implements org.apache.ibatis.type.TypeHandler. A class that resolves fine but is not a TypeHandler implementation fails with this BuilderException.

Source

Thrown at src/main/java/org/apache/ibatis/builder/BaseBuilder.java:122

      throw new BuilderException("Error resolving class. Cause: " + e, e);
    }
  }

  @Deprecated(since = "3.6.0", forRemoval = true)
  protected TypeHandler<?> resolveTypeHandler(Class<?> javaType, String typeHandlerAlias) {
    return resolveTypeHandler(javaType, null, typeHandlerAlias);
  }

  @Deprecated(since = "3.6.0", forRemoval = true)
  protected TypeHandler<?> resolveTypeHandler(Class<?> javaType, Class<? extends TypeHandler<?>> typeHandlerType) {
    return resolveTypeHandler(javaType, null, typeHandlerType);
  }

  protected TypeHandler<?> resolveTypeHandler(Type propertyType, JdbcType jdbcType, String typeHandlerAlias) {
    Class<? extends TypeHandler<?>> typeHandlerType = null;
    typeHandlerType = resolveClass(typeHandlerAlias);
    if (typeHandlerType != null && !TypeHandler.class.isAssignableFrom(typeHandlerType)) {
      throw new BuilderException("Type " + typeHandlerType.getName()
          + " is not a valid TypeHandler because it does not implement TypeHandler interface");
    }
    return resolveTypeHandler(propertyType, jdbcType, typeHandlerType);
  }

  protected TypeHandler<?> resolveTypeHandler(Type javaType, JdbcType jdbcType,
      Class<? extends TypeHandler<?>> typeHandlerType) {
    if (typeHandlerType == null && jdbcType == null) {
      return null;
    }
    return configuration.getTypeHandlerRegistry().getTypeHandler(javaType, jdbcType, typeHandlerType);
  }

  protected <T> Class<? extends T> resolveAlias(String alias) {
    return typeAliasRegistry.resolveAlias(alias);
  }
}

View on GitHub (pinned to 008069adb1)

Solutions

  1. Make the referenced class implement/extend TypeHandler/BaseTypeHandler<T>
  2. Eliminate duplicate mybatis jars on the classpath so a single TypeHandler interface is used
  3. Recompile custom handlers against the mybatis version in use

Example fix

<!-- before -->
<result column="data" property="data" typeHandler="com.example.JsonUtil"/>
<!-- after -->
public class JsonTypeHandler extends BaseTypeHandler<MyJson> { ... }
<result column="data" property="data" typeHandler="com.example.JsonTypeHandler"/>
Defensive patterns

Strategy: type-guard

Validate before calling

Class<?> c = Class.forName(typeHandlerName);
if (!org.apache.ibatis.type.TypeHandler.class.isAssignableFrom(c)) {
  throw new IllegalStateException(typeHandlerName + " is not a TypeHandler");
}

Type guard

static boolean isTypeHandler(Class<?> c) {
  return org.apache.ibatis.type.TypeHandler.class.isAssignableFrom(c);
}

Prevention

When it happens

Trigger: typeHandler="com.example.SomeUtil" where SomeUtil is a plain utility class; passing a class that only extends a BaseTypeHandler indirectly through generics but was compiled against an incompatible mybatis version (binary incompatibility); specifying a TypeException class or ResultSetHandler where a TypeHandler was expected.

Common situations: Copy-pasting the wrong class name into a typeHandler attribute; multiple mybatis jar versions on the classpath so the class implements a different TypeHandler class (different classloader/package); upgrading MyBatis with a custom handler compiled against the old API.

Related errors


AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14). Data as JSON: /api/errors/0ca817be59a68a1f. Report an issue: GitHub.