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
- Read the chained 'Cause:' exception first - it names the real failure (IllegalAccessException, etc.)
- For JPMS, open/export the mapper's package to org.apache.ibatis or add the needed --add-opens JVM flags
- 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
- Keep mybatis and mapper interfaces in the same classloader (no duplicated jars across webapp/container)
- For JPMS deployments, add --add-opens for mapper packages
- Always log the chained cause; the root reason is never the wrapper message
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
- Unknown execution method for: {name}
- Mapper method '{name}' attempted to return null from a metho
- Mapper method '{name}' has an unsupported return type: {retu
- method {name} needs either a @ResultMap annotation, a @Resul
- Parameter '{key}' not found. Available parameters are {keySe
AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14).
Data as JSON: /api/errors/365a4fe2ccf1e93e.
Report an issue: GitHub.