baomidou/mybatis-plus · error · BindingException
Mapper method '%s' attempted to return null from a method wi
Error message
Mapper method '%s' attempted to return null from a method with a primitive return type (%s).
What it means
The executed statement returned null but the mapper method's return type is a primitive (int, long, boolean...). Java cannot represent null for primitives, so the mapper method invocation fails rather than silently returning 0/false. The message names the offending method and its primitive type.
Source
Thrown at mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/override/MybatisMapperMethod.java:124
result = executeForIPage(sqlSession, args);
} else {
Object param = this.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
if (method.returnsOptional()
&& (result == null || !method.getReturnType().equals(result.getClass()))) {
result = Optional.ofNullable(result);
}
}
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + command.getName());
}
if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
throw new BindingException("Mapper method '" + command.getName()
+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
}
return result;
}
@SuppressWarnings("all")
private <E> Object executeForIPage(SqlSession sqlSession, Object[] args) {
IPage<E> result = null;
for (Object arg : args) {
if (arg instanceof IPage) {
result = (IPage<E>) arg;
break;
}
}
Assert.notNull(result, "can't found IPage for args!");
Object param = this.convertArgsToSqlCommandParam(args);
List<E> list = sqlSession.selectList(command.getName(), param);
result.setRecords(list);View on GitHub (pinned to bf67d90747)
Solutions
- Change the mapper method return type to the wrapper class (Integer/Long/Boolean) and null-check at the call site
- If an interceptor is returning null, fix it to return an empty/appropriate result
- Verify the statement really returns a value for the given call shape
Example fix
// before
int countAdults(@Param("age") int age);
// after
Integer countAdults(@Param("age") int age);
// call site
int n = Optional.ofNullable(mapper.countAdults(18)).orElse(0); Defensive patterns
Strategy: type-guard
Type guard
// Enforce non-primitive returns on mapper write methods with a ArchUnit-style rule:
// methods declared on *Mapper interfaces that bind to INSERT/UPDATE/DELETE must return
// void | Integer | int | Long | long | Boolean | boolean
static boolean legalWriteReturn(Class<?> rt) {
return rt == void.class || rt == Void.class || rt == Integer.class || rt == int.class
|| rt == Long.class || rt == long.class || rt == Boolean.class || rt == boolean.class;
} Try / catch
catch BindingException at the call site only to log which method/return type collided; the real fix is the signature — no retry helps.
Prevention
- Use wrapper types (Integer/Long/Boolean) for mapper method returns
- Null-check results with Optional.ofNullable(...).orElse(default) at call sites
- Audit interceptors that may return null from query interception
When it happens
Trigger: A mapper method declared 'int count(...)' or 'boolean exists(...)' whose SQL/procedure path yields no result object (e.g. a stored procedure returning void in a SELECT-shaped call, or an interceptor returning null from query interception).
Common situations: Interceptors (e.g. tenant/data-permission plugins) short-circuiting and returning null; calling a PROCEDURE as if it returned a value; method signatures written with primitives for stylistic brevity.
Related errors
- %s already contains value for %s
- %s does not contain value for %s
- Mapper's namespace cannot be empty
- Error parsing Mapper XML. The XML location is '%s'. Cause: %
- Mapper method '%s' has an unsupported return type: %s
AI-assisted analysis of baomidou/mybatis-plus@bf67d90747 (2026-08-14).
Data as JSON: /api/errors/947d216e044314bb.
Report an issue: GitHub.