{"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/e8729d043887bf0d0baf91e062e909b56eb2b708/spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java#L274-L310","documentation":"The base AbstractAspectJAdvice.setReturningName(String) (line 291-293) is intentionally a guard: it throws UnsupportedOperationException because only after-returning advice semantics can bind a return value. The concrete AspectJAfterReturningAdvice overrides this method; calling it on any other advice subtype (before, after, after-throwing, around) hits this guard.","triggerScenarios":"Invoking setReturningName on an AspectJMethodBeforeAdvice, AspectJAfterAdvice, AspectJAfterThrowingAdvice, or AspectJAroundAdvice instance, or configuring a 'returning' attribute on an <aop:before>, <aop:after>, <aop:after-throwing>, or <aop:around> element.","commonSituations":"XML misconfiguration: putting returning=\"ret\" on the wrong advice element; copy-pasting an after-returning block and changing the advice kind without removing 'returning'; programmatically building advice objects and generically calling setReturningName.","solutions":["Move the 'returning' attribute onto an <aop:after-returning> element (or @AfterReturning advice) only.","Remove the 'returning' attribute from the before/after/after-throwing/around element causing the error.","If binding a return value is genuinely needed, switch that advice to after-returning semantics.","When building advice programmatically, only call setReturningName on an AspectJAfterReturningAdvice instance."],"exampleFix":"// before\n<aop:aspect ref=\"audit\">\n  <aop:after-throwing method=\"onEx\" pointcut=\"...\" returning=\"ret\"/>\n</aop:aspect>\n// after\n<aop:aspect ref=\"audit\">\n  <aop:after-returning method=\"onRet\" pointcut=\"...\" returning=\"ret\"/>\n</aop:aspect>","handlingStrategy":"validation","validationCode":"// Only call setReturningName on the correct advice subtype.\nif (advice instanceof AspectJAfterReturningAdvice) {\n    advice.setReturningName(name);\n} else {\n    throw new IllegalStateException(\"returning binding requires after-returning advice, got \" + advice.getClass());\n}","typeGuard":"private static boolean supportsReturning(AbstractAspectJAdvice a) {\n    return a instanceof AspectJAfterReturningAdvice;\n}","tryCatchPattern":"try {\n    advice.setReturningName(name);\n} catch (UnsupportedOperationException ex) {\n    throw new IllegalStateException(\n        \"'returning' is only valid on after-returning advice; remove it from \" + advice.getClass().getSimpleName(), ex);\n}","preventionTips":["Place 'returning' only on after-returning advice (XML element or @AfterReturning).","When templating advice XML, change the advice kind and remove returning/throwing together.","Programmatic advice construction: branch on advice type before setting returning/throwing."],"tags":["spring-aop","aspectj","after-returning","configuration","misuse"],"analyzedSha":"e8729d043887bf0d0baf91e062e909b56eb2b708","analyzedAt":"2026-08-04T19:07:39.725Z","schemaVersion":2}