{"record":{"id":"af7ae38958aef30f","repo":"spring-projects/spring-framework","slug":"only-afterreturning-advice-can-be-used-to-bind-a-r","errorCode":null,"errorMessage":"Only afterReturning advice can be used to bind a return value","messagePattern":"Only afterReturning advice can be used to bind a return value","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java","lineNumber":292,"sourceCode":"\t\t\t// May need to add implicit join point arg name...\n\t\t\tfor (int i = 0; i < this.aspectJAdviceMethod.getParameterCount(); i++) {\n\t\t\t\tClass<?> argType = this.aspectJAdviceMethod.getParameterTypes()[i];\n\t\t\t\tif (argType == JoinPoint.class ||\n\t\t\t\t\t\targType == ProceedingJoinPoint.class ||\n\t\t\t\t\t\targType == JoinPoint.StaticPart.class) {\n\t\t\t\t\t@Nullable String[] oldNames = this.argumentNames;\n\t\t\t\tthis.argumentNames = new String[oldNames.length + 1];\n\t\t\t\tSystem.arraycopy(oldNames, 0, this.argumentNames, 0, i);\n\t\t\t\t\tthis.argumentNames[i] = \"THIS_JOIN_POINT\";\n\t\t\t\t\tSystem.arraycopy(oldNames, i, this.argumentNames, i + 1, oldNames.length - i);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic void setReturningName(String name) {\n\t\tthrow new UnsupportedOperationException(\"Only afterReturning advice can be used to bind a return value\");\n\t}\n\n\t/**\n\t * We need to hold the returning name at this level for argument binding calculations,\n\t * this method allows the afterReturning advice subclass to set the name.\n\t */\n\tprotected void setReturningNameNoCheck(String name) {\n\t\t// name could be a variable or a type...\n\t\tif (isVariableName(name)) {\n\t\t\tthis.returningName = name;\n\t\t}\n\t\telse {\n\t\t\t// assume a type\n\t\t\ttry {\n\t\t\t\tthis.discoveredReturningType = ClassUtils.forName(name, getAspectClassLoader());\n\t\t\t}\n\t\t\tcatch (Throwable ex) {\n\t\t\t\tthrow new IllegalArgumentException(\"Returning name '\" + name +","sourceCodeStart":274,"sourceCodeEnd":310,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/69bf83ad716d0cfc4b0520a19b4d8b24c79d1538/spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java#L274-L310","documentation":"The base AbstractAspectJAdvice.setReturningName(String) at line 291-293 always throws UnsupportedOperationException. Only AspectJAfterReturningAdvice overrides it to delegate to setReturningNameNoCheck. Binding a return value is semantically meaningless for before/around/after-throwing advice, so the base class forbids it.","triggerScenarios":"Calling setReturningName(\"retVal\") on an instance of AspectJMethodBeforeAdvice, AspectJAroundAdvice, or AspectJAfterThrowingAdvice — or configuring a 'returning' attribute on an <aop:before>, <aop:around>, or <aop:after-throwing> element. Also triggered programmatically when reusing a generic advice-registration routine that always sets returning.","commonSituations":"XML config where a 'returning=\"...\"' attribute is copy-pasted onto the wrong advice element, or a programmatic advisor builder that unconditionally calls setReturningName. Also happens when migrating an after-returning aspect to after-throwing without removing the returning clause.","solutions":["Move the 'returning' binding to an @AfterReturning / <aop:after-returning> advice — it is the only advice type that supports it.","If building advice programmatically, check the concrete type (instanceof AspectJAfterReturningAdvice) before calling setReturningName.","Remove the 'returning' attribute from the offending before/around/after-throwing element."],"exampleFix":"// before — returning on a before advice (invalid)\n<aop:before method=\"check\"\n    pointcut=\"execution(* *(..))\" returning=\"retVal\"/>\n\n// after — use after-returning advice to bind the return value\n<aop:after-returning method=\"onSuccess\"\n    pointcut=\"execution(* *(..))\" returning=\"retVal\"/>","handlingStrategy":"type-guard","validationCode":"import org.springframework.aop.aspectj.AspectJAfterReturningAdvice;\n\n// Only call setReturningName on after-returning advice.\nvoid safeSetReturningName(AbstractAspectJAdvice advice, String name) {\n    if (advice instanceof AspectJAfterReturningAdvice) {\n        advice.setReturningName(name);\n    } else {\n        throw new IllegalStateException(\"returning binding requires AspectJAfterReturningAdvice\");\n    }\n}","typeGuard":"boolean supportsReturningBinding(AbstractAspectJAdvice advice) {\n    return advice instanceof org.springframework.aop.aspectj.AspectJAfterReturningAdvice;\n}","tryCatchPattern":"try {\n    advice.setReturningName(\"retVal\");\n} catch (UnsupportedOperationException ex) {\n    // returning is only valid for afterReturning advice; remove the attribute\n}","preventionTips":["Apply 'returning' only to @AfterReturning / <aop:after-returning>.","In programmatic registrars, branch on the concrete advice type before setting returning.","Review XML on every advice-type change."],"tags":["spring-aop","aspectj","after-returning","advice-type","configuration"],"backgroundTag":null,"analyzedSha":"69bf83ad716d0cfc4b0520a19b4d8b24c79d1538","analyzedAt":"2026-08-09T15:32:58.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}