{"record":{"id":"b2840068ed749344","repo":"spring-projects/spring-framework","slug":"null-return-value-from-advice-does-not-match-primi","errorCode":null,"errorMessage":"Null return value from advice does not match primitive return type for: {}","messagePattern":"Null return value from advice does not match primitive return type for: (.+?)","errorType":"exception","errorClass":"AopInvocationException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java","lineNumber":435,"sourceCode":"\n\t/**\n\t * Process a return value. Wraps a return of {@code this} if necessary to be the\n\t * {@code proxy} and also verifies that {@code null} is not returned as a primitive.\n\t * Also takes care of the conversion from {@code Mono} to Kotlin Coroutines if needed.\n\t */\n\tprivate static @Nullable Object processReturnType(\n\t\t\tObject proxy, @Nullable Object target, Method method, Object[] arguments, @Nullable Object returnValue) {\n\n\t\t// Massage return value if necessary\n\t\tif (returnValue != null && returnValue == target &&\n\t\t\t\t!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {\n\t\t\t// Special case: it returned \"this\". Note that we can't help\n\t\t\t// if the target sets a reference to itself in another returned object.\n\t\t\treturnValue = proxy;\n\t\t}\n\t\tClass<?> returnType = method.getReturnType();\n\t\tif (returnValue == null && returnType != void.class && returnType.isPrimitive()) {\n\t\t\tthrow new AopInvocationException(\n\t\t\t\t\t\"Null return value from advice does not match primitive return type for: \" + method);\n\t\t}\n\t\tif (COROUTINES_REACTOR_PRESENT && KotlinDetector.isSuspendingFunction(method)) {\n\t\t\treturn COROUTINES_FLOW_CLASS_NAME.equals(new MethodParameter(method, -1).getParameterType().getName()) ?\n\t\t\t\t\tCoroutinesUtils.asFlow(returnValue) :\n\t\t\t\t\tCoroutinesUtils.awaitSingleOrNull(returnValue, arguments[arguments.length - 1]);\n\t\t}\n\t\treturn returnValue;\n\t}\n\n\n\t/**\n\t * Serializable replacement for CGLIB's NoOp interface.\n\t * Public to allow use elsewhere in the framework.\n\t */\n\tpublic static class SerializableNoOp implements NoOp, Serializable {\n\t}\n","sourceCodeStart":417,"sourceCodeEnd":453,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/69bf83ad716d0cfc4b0520a19b4d8b24c79d1538/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java#L417-L453","documentation":"CglibAopProxy.processReturnType() (line 423) inspects each invocation's return. If the target method declares a primitive return type (e.g. int) but the advice chain yields null (an Around advice returned null, or the target returned null via a boxed path), Spring throws AopInvocationException at line 435 because unboxing null to a primitive is impossible and would otherwise produce a confusing NPE.","triggerScenarios":"An @Around (or other advice that controls the return) returns null for a joinpoint whose method has a primitive return type; the target method returns null through a proxy path that loses autoboxing.","commonSituations":"An @Around advice that returns null on some branch (e.g. cache miss returning null, or short-circuit) for a method declared to return int/boolean/long; caching/aspect that forgets to call proceed() and returns null.","solutions":["In the @Around advice, never return null when the proxied method returns a primitive - return a proper default (0, false, etc.) or the result of proceed()","Ensure proceeding.joinPoint.proceed() is always invoked and its result returned for primitive-returning methods","Unit-test the advice against a primitive-returning method to catch null returns early"],"exampleFix":"// before\n@Around(\"...\")\npublic Object cache(ProceedingJoinPoint pjp) {\n  if (cacheMiss) return null;  // method returns int -> boom\n  return pjp.proceed();\n}\n\n// after\n@Around(\"...\")\npublic Object cache(ProceedingJoinPoint pjp) throws Throwable {\n  if (cacheMiss) return 0;  // match primitive return type\n  return pjp.proceed();\n}","handlingStrategy":"validation","validationCode":"// Inside @Around, guard null returns for primitive methods:\nObject result = pjp.proceed();\nif (result == null && pjp.getSignature() instanceof MethodSignature ms\n    && ms.getReturnType().isPrimitive()) {\n  return Defaults.defaultValue(ms.getReturnType());\n}\nreturn result;","typeGuard":"private static boolean returnsPrimitive(Method m) {\n  return m != null && m.getReturnType().isPrimitive();\n}","tryCatchPattern":null,"preventionTips":["Never return null from @Around advice for primitive-returning methods","Always return proceed() (or a primitive-compatible default) in advice"],"tags":["spring-aop","cglib","advice","primitive-return"],"backgroundTag":null,"analyzedSha":"69bf83ad716d0cfc4b0520a19b4d8b24c79d1538","analyzedAt":"2026-08-09T15:32:58.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}