{"record":{"id":"947d216e044314bb","repo":"baomidou/mybatis-plus","slug":"mapper-method-s-attempted-to-return-null-from-a","errorCode":null,"errorMessage":"Mapper method '%s' attempted to return null from a method with a primitive return type (%s).","messagePattern":"Mapper method '(.+?)' attempted to return null from a method with a primitive return type \\((.+?)\\)\\.","errorType":"exception","errorClass":"BindingException","httpStatus":null,"severity":"error","filePath":"mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/override/MybatisMapperMethod.java","lineNumber":124,"sourceCode":"                        result = executeForIPage(sqlSession, args);\n                    } else {\n                        Object param = this.convertArgsToSqlCommandParam(args);\n                        result = sqlSession.selectOne(command.getName(), param);\n                        if (method.returnsOptional()\n                            && (result == null || !method.getReturnType().equals(result.getClass()))) {\n                            result = Optional.ofNullable(result);\n                        }\n                    }\n                }\n                break;\n            case FLUSH:\n                result = sqlSession.flushStatements();\n                break;\n            default:\n                throw new BindingException(\"Unknown execution method for: \" + command.getName());\n        }\n        if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {\n            throw new BindingException(\"Mapper method '\" + command.getName()\n                + \" attempted to return null from a method with a primitive return type (\" + method.getReturnType() + \").\");\n        }\n        return result;\n    }\n\n    @SuppressWarnings(\"all\")\n    private <E> Object executeForIPage(SqlSession sqlSession, Object[] args) {\n        IPage<E> result = null;\n        for (Object arg : args) {\n            if (arg instanceof IPage) {\n                result = (IPage<E>) arg;\n                break;\n            }\n        }\n        Assert.notNull(result, \"can't found IPage for args!\");\n        Object param = this.convertArgsToSqlCommandParam(args);\n        List<E> list = sqlSession.selectList(command.getName(), param);\n        result.setRecords(list);","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/baomidou/mybatis-plus/blob/bf67d907478c724120bf76292da54abf9e73c2b3/mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/override/MybatisMapperMethod.java#L106-L142","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"// before\nint countAdults(@Param(\"age\") int age);\n// after\nInteger countAdults(@Param(\"age\") int age);\n// call site\nint n = Optional.ofNullable(mapper.countAdults(18)).orElse(0);","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// Enforce non-primitive returns on mapper write methods with a ArchUnit-style rule:\n// methods declared on *Mapper interfaces that bind to INSERT/UPDATE/DELETE must return\n// void | Integer | int | Long | long | Boolean | boolean\nstatic boolean legalWriteReturn(Class<?> rt) {\n    return rt == void.class || rt == Void.class || rt == Integer.class || rt == int.class\n        || rt == Long.class || rt == long.class || rt == Boolean.class || rt == boolean.class;\n}","tryCatchPattern":"catch BindingException at the call site only to log which method/return type collided; the real fix is the signature — no retry helps.","preventionTips":["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"],"tags":["mybatis","mapper","primitive-return","null"],"backgroundTag":null,"analyzedSha":"bf67d907478c724120bf76292da54abf9e73c2b3","analyzedAt":"2026-08-14T15:17:09.543Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}