spring-projects/spring-framework · error · UnsupportedOperationException
Only afterThrowing advice can be used to bind a thrown…
Error message
Only afterThrowing advice can be used to bind a thrown exception
What it means
The base AbstractAspectJAdvice.setThrowingName(String) at line 325-327 always throws UnsupportedOperationException. Only AspectJAfterThrowingAdvice overrides it to delegate to setThrowingNameNoCheck. Binding a thrown exception is semantically valid only for after-throwing advice, so every other advice type refuses it.
Solutions
- Move the 'throwing' binding to an @AfterThrowing / <aop:after-throwing> advice — the only type that supports it.
- Remove the 'throwing' attribute from the offending before/around/after-returning element.
- If registering programmatically, guard setThrowingName with an instanceof AspectJAfterThrowingAdvice check.
Example fix
// before — throwing on after-returning (invalid)
<aop:after-returning method="after"
pointcut="execution(* *(..))" throwing="ex"/>
// after — use after-throwing advice to bind the exception
<aop:after-throwing method="onError"
pointcut="execution(* *(..))" throwing="ex"/> Defensive patterns
Strategy: type-guard
Validate before calling
import org.springframework.aop.aspectj.AspectJAfterThrowingAdvice;
void safeSetThrowingName(AbstractAspectJAdvice advice, String name) {
if (advice instanceof AspectJAfterThrowingAdvice) {
advice.setThrowingName(name);
} else {
throw new IllegalStateException("throwing binding requires AspectJAfterThrowingAdvice");
}
} Type guard
boolean supportsThrowingBinding(AbstractAspectJAdvice advice) {
return advice instanceof org.springframework.aop.aspectj.AspectJAfterThrowingAdvice;
} Try / catch
try {
advice.setThrowingName("ex");
} catch (UnsupportedOperationException ex) {
// throwing is only valid for afterThrowing advice; remove the attribute
} Prevention
- Apply 'throwing' only to @AfterThrowing / <aop:after-throwing>.
- Branch on concrete advice type in programmatic registrars.
- Re-check XML after converting between advice types.
When it happens
Trigger: Calling setThrowingName("ex") on an instance of AspectJMethodBeforeAdvice, AspectJAroundAdvice, or AspectJAfterReturningAdvice, or configuring a 'throwing' attribute on <aop:before>, <aop:around>, or <aop:after-returning>. Also triggered by a generic programmatic registrar that always sets throwing.
Common situations: XML/annotation config where a 'throwing="..."' attribute lands on the wrong advice element, or a shared advisor builder that unconditionally calls setThrowingName. Typical when copying an after-throwing block and forgetting to change the advice kind.
Related errors
- Only afterReturning advice can be used to bind a return…
- 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/7ace6b6180ba2a12.
Report an issue: GitHub.
Appendix: source
Thrown at spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java:326
}
catch (Throwable ex) {
throw new IllegalArgumentException("Returning name '" + name +
"' is neither a valid argument name nor the fully-qualified " +
"name of a Java type on the classpath. Root cause: " + ex);
}
}
}
protected Class<?> getDiscoveredReturningType() {
return this.discoveredReturningType;
}
protected @Nullable Type getDiscoveredReturningGenericType() {
return this.discoveredReturningGenericType;
}
public void setThrowingName(String name) {
throw new UnsupportedOperationException("Only afterThrowing advice can be used to bind a thrown exception");
}
/**
* We need to hold the throwing name at this level for argument binding calculations,
* this method allows the afterThrowing advice subclass to set the name.
*/
protected void setThrowingNameNoCheck(String name) {
// name could be a variable or a type...
if (isVariableName(name)) {
this.throwingName = name;
}
else {
// assume a type
try {
this.discoveredThrowingType = ClassUtils.forName(name, getAspectClassLoader());
}
catch (Throwable ex) {
throw new IllegalArgumentException("Throwing name '" + name +View on GitHub (pinned to 69bf83ad71)