mybatis/mybatis-3 · error · BindingException

Mapper method '{name}' attempted to return null from a metho

Error message

Mapper method '{name}' attempted to return null from a method with a primitive return type ({returnType}).

What it means

A mapper method declared with a primitive return type (int, boolean, long, ...) executed a query that returned null. Java cannot unbox null into a primitive, so MyBatis fails fast with a BindingException instead of throwing a bare NullPointerException at the call site.

Source

Thrown at src/main/java/org/apache/ibatis/binding/MapperMethod.java:100

          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {
          result = executeForCursor(sqlSession, args);
        } else {
          Object param = method.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;
  }

  private Object rowCountResult(int rowCount) {
    final Object result;
    if (method.returnsVoid()) {
      result = null;
    } else if (Integer.class.equals(method.getReturnType()) || Integer.TYPE.equals(method.getReturnType())) {
      result = rowCount;
    } else if (Long.class.equals(method.getReturnType()) || Long.TYPE.equals(method.getReturnType())) {
      result = (long) rowCount;
    } else if (Boolean.class.equals(method.getReturnType()) || Boolean.TYPE.equals(method.getReturnType())) {
      result = rowCount > 0;
    } else {
      throw new BindingException(
          "Mapper method '" + command.getName() + "' has an unsupported return type: " + method.getReturnType());

View on GitHub (pinned to 008069adb1)

Solutions

  1. Change the mapper method return type from primitive to its wrapper (int -> Integer, boolean -> Boolean) and handle null at the call site
  2. If the query should always return a row, fix the WHERE clause or the data so a row is always matched
  3. Add COALESCE/IFNULL in SQL so the database returns a non-null scalar instead of no row

Example fix

// before
int findAge(@Param("id") Long id);
// after
Integer findAge(@Param("id") Long id); // caller handles null
Defensive patterns

Strategy: type-guard

Type guard

static boolean safePrimitiveReturn(Class<?> rt) {
  return !rt.isPrimitive(); // prefer wrappers in mapper signatures
}

Try / catch

catch (BindingException e) { if (e.getMessage().contains("primitive return type")) return defaultValue; throw e; }

Prevention

When it happens

Trigger: Mapper method like 'int findAge(Long id)' where selectOne returns no row; INSERT/UPDATE/DELETE methods declared with primitive types not covered by rowCountResult (which does handle int/long/boolean); a SELECT method with primitive return whose query yields zero rows.

Common situations: Querying by an id that does not exist; filters that match nothing; changing a wrapper return type (Integer) to a primitive (int) during refactoring.

Related errors


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