mybatis/mybatis-3 · error · BindingException

Error getting mapper instance. Cause: {cause}

Error message

Error getting mapper instance. Cause: {cause}

What it means

MapperProxyFactory.newInstance() failed while creating the JDK dynamic proxy for the mapper interface. The cause is chained in the message ('Cause: ...'); typical causes are failures in instantiating the proxy, errors thrown from mapper interface default methods during construction of the invoker cache, or classloader issues in managed environments.

Source

Thrown at src/main/java/org/apache/ibatis/binding/MapperRegistry.java:52

public class MapperRegistry {

  private final Configuration config;
  private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new ConcurrentHashMap<>();

  public MapperRegistry(Configuration config) {
    this.config = config;
  }

  @SuppressWarnings("unchecked")
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }

  public <T> boolean hasMapper(Class<T> type) {
    return knownMappers.containsKey(type);
  }

  public <T> void addMapper(Class<T> type) {
    if (type.isInterface()) {
      if (hasMapper(type)) {
        throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
      }
      boolean loadCompleted = false;
      try {
        knownMappers.put(type, new MapperProxyFactory<>(type));
        // It's important that the type is added before the parser is run
        // otherwise the binding may automatically be attempted by the
        // mapper parser. If the type is already known, it won't try.

View on GitHub (pinned to 008069adb1)

Solutions

  1. Read the chained 'Cause:' exception first - it names the real failure (IllegalAccessException, etc.)
  2. For JPMS, open/export the mapper's package to org.apache.ibatis or add the needed --add-opens JVM flags
  3. Ensure one classloader loads both mybatis and the mapper interfaces (avoid duplicated jars across webapp and container libs)

Example fix

# example JPMS fix
java --add-opens com.example.mappers/com.example.mappers=org.apache.ibatis ...
Defensive patterns

Strategy: try-catch

Try / catch

try {
  FooMapper m = session.getMapper(FooMapper.class);
} catch (BindingException e) {
  log.error("Mapper proxy creation failed: {}", e.getCause().getMessage(), e.getCause());
  throw e; // classloader/module problems are not recoverable at runtime
}

Prevention

When it happens

Trigger: Any reflective failure while building the MapperProxy: e.g. inaccessible default methods under strict module boundaries (Java 16+ strong encapsulation), a SecurityManager denying proxy creation, or classloader mismatch (mapper interface visible to a different loader than MyBatis).

Common situations: App servers with parent-last classloading; OSGi containers; JPMS deployments where org.apache.ibatis cannot access the mapper interface; finalizing environments where reflection is restricted.

Related errors


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