spring-projects/spring-framework · error · UnsupportedOperationException
Only afterReturning advice can be used to bind a return…
Error message
Only afterReturning advice can be used to bind a return value
What it means
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.
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.
Example fix
// before — returning on a before advice (invalid)
<aop:before method="check"
pointcut="execution(* *(..))" returning="retVal"/>
// after — use after-returning advice to bind the return value
<aop:after-returning method="onSuccess"
pointcut="execution(* *(..))" returning="retVal"/> Defensive patterns
Strategy: type-guard
Validate before calling
import org.springframework.aop.aspectj.AspectJAfterReturningAdvice;
// Only call setReturningName on after-returning advice.
void safeSetReturningName(AbstractAspectJAdvice advice, String name) {
if (advice instanceof AspectJAfterReturningAdvice) {
advice.setReturningName(name);
} else {
throw new IllegalStateException("returning binding requires AspectJAfterReturningAdvice");
}
} Type guard
boolean supportsReturningBinding(AbstractAspectJAdvice advice) {
return advice instanceof org.springframework.aop.aspectj.AspectJAfterReturningAdvice;
} Try / catch
try {
advice.setReturningName("retVal");
} catch (UnsupportedOperationException ex) {
// returning is only valid for afterReturning advice; remove the attribute
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Only afterThrowing advice can be used to bind a thrown…
- Advice must be declared inside an aspect type: Offending…
- 'argumentNames' property of AbstractAspectJAdvice contains…
- is not an @AspectJ aspect
- uses percflow instantiation model: This is not supported in…
AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09).
Data as JSON: /api/errors/af7ae38958aef30f.
Report an issue: GitHub.
Appendix: source
Thrown at spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java:292
// May need to add implicit join point arg name...
for (int i = 0; i < this.aspectJAdviceMethod.getParameterCount(); i++) {
Class<?> argType = this.aspectJAdviceMethod.getParameterTypes()[i];
if (argType == JoinPoint.class ||
argType == ProceedingJoinPoint.class ||
argType == JoinPoint.StaticPart.class) {
@Nullable String[] oldNames = this.argumentNames;
this.argumentNames = new String[oldNames.length + 1];
System.arraycopy(oldNames, 0, this.argumentNames, 0, i);
this.argumentNames[i] = "THIS_JOIN_POINT";
System.arraycopy(oldNames, i, this.argumentNames, i + 1, oldNames.length - i);
break;
}
}
}
}
public void setReturningName(String name) {
throw new UnsupportedOperationException("Only afterReturning advice can be used to bind a return value");
}
/**
* We need to hold the returning name at this level for argument binding calculations,
* this method allows the afterReturning advice subclass to set the name.
*/
protected void setReturningNameNoCheck(String name) {
// name could be a variable or a type...
if (isVariableName(name)) {
this.returningName = name;
}
else {
// assume a type
try {
this.discoveredReturningType = ClassUtils.forName(name, getAspectClassLoader());
}
catch (Throwable ex) {
throw new IllegalArgumentException("Returning name '" + name +View on GitHub (pinned to 69bf83ad71)