spring-projects/spring-framework · error · IllegalStateException
Returning argument name
Error message
Returning argument name '{}' was not bound in advice arguments What it means
Thrown by bindExplicitArguments (line 486-490) when returningName is set but does not appear as a key in the computed argumentBindings map. The returning name must match one of the advice method's parameter names so Spring knows which slot receives the return value. A mismatch means the configured 'returning' cannot be matched to a parameter.
Solutions
- Ensure the returning name exactly matches an advice method parameter name (case-sensitive).
- Compile with -parameters so the real parameter name is discovered and matches returning.
- If returning was meant as a type restriction, instead declare a parameter of that type and bind by variable name.
- Re-check that arg-names (if used) includes the returning name.
Example fix
// before — returning name does not match the parameter
@AfterReturning(pointcut="execution(* svc.*(..))", returning="retVal")
public void after(Object result) { ... }
// after — names agree
@AfterReturning(pointcut="execution(* svc.*(..))", returning="result")
public void after(Object result) { ... } Defensive patterns
Strategy: validation
Validate before calling
import java.lang.reflect.Method;
import java.util.Arrays;
// Verify the returning name matches an actual parameter name before binding.
void assertReturningNameBound(Method adviceMethod, String returningName, String[] discoveredNames) {
String[] names = discoveredNames != null ? discoveredNames
: new org.springframework.core.DefaultParameterNameDiscoverer().getParameterNames(adviceMethod);
if (names == null || !Arrays.asList(names).contains(returningName)) {
throw new IllegalStateException("returning '" + returningName + "' not found among params " + Arrays.toString(names));
}
} Type guard
boolean returningNameMatchesParam(Method m, String returningName) {
String[] names = new org.springframework.core.DefaultParameterNameDiscoverer().getParameterNames(m);
return names != null && java.util.Arrays.asList(names).contains(returningName);
} Try / catch
try {
advice.getPointcut();
} catch (IllegalStateException ex) {
if (ex.getMessage().contains("Returning argument name") && ex.getMessage().contains("not bound")) {
// align the returning attribute with the actual parameter name
} else { throw ex; }
} Prevention
- Keep the returning attribute and the parameter name identical.
- Compile with -parameters so names are always available.
- Re-check the returning attribute after renaming advice parameters.
When it happens
Trigger: Configuring returning="retVal" but the advice method parameter is named differently (e.g. 'result'), and parameter names were supplied/ discovered under the wrong identifier. Also when returning is set to a type-restriction string but no parameter matches that binding slot.
Common situations: Renaming an advice parameter without updating the returning attribute, or vice versa. Compiling without -parameters so the discovered name differs from the returning name. Mismatched XML returning vs @AfterReturning(returning=).
Related errors
- Returning name ' ' is neither a valid argument name nor the…
- Throwing argument name
- Advice method [ ] requires arguments to be bound by name…
- 'argumentNames' property of AbstractAspectJAdvice contains…
- Binding of returning parameter
AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09).
Data as JSON: /api/errors/f02139f6ed8b1ffb.
Report an issue: GitHub.
Appendix: source
Thrown at spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java:488
int numExpectedArgumentNames = this.aspectJAdviceMethod.getParameterCount();
if (this.argumentNames.length != numExpectedArgumentNames) {
throw new IllegalStateException("Expecting to find " + numExpectedArgumentNames +
" arguments to bind by name in advice, but actually found " +
this.argumentNames.length + " arguments.");
}
// So we match in number...
int argumentIndexOffset = this.parameterTypes.length - numArgumentsLeftToBind;
for (int i = argumentIndexOffset; i < this.argumentNames.length; i++) {
this.argumentBindings.put(this.argumentNames[i], i);
}
// Check that returning and throwing were in the argument names list if
// specified, and find the discovered argument types.
if (this.returningName != null) {
if (!this.argumentBindings.containsKey(this.returningName)) {
throw new IllegalStateException("Returning argument name '" + this.returningName +
"' was not bound in advice arguments");
}
else {
Integer index = this.argumentBindings.get(this.returningName);
this.discoveredReturningType = this.aspectJAdviceMethod.getParameterTypes()[index];
this.discoveredReturningGenericType = this.aspectJAdviceMethod.getGenericParameterTypes()[index];
}
}
if (this.throwingName != null) {
if (!this.argumentBindings.containsKey(this.throwingName)) {
throw new IllegalStateException("Throwing argument name '" + this.throwingName +
"' was not bound in advice arguments");
}
else {
Integer index = this.argumentBindings.get(this.throwingName);
this.discoveredThrowingType = this.aspectJAdviceMethod.getParameterTypes()[index];
}
}View on GitHub (pinned to 69bf83ad71)