spring-projects/spring-framework · error · IllegalStateException
Not enough arguments in method to satisfy binding of…
Error message
Not enough arguments in method to satisfy binding of returning and throwing variables
What it means
Thrown by AspectJAdviceParameterNameDiscoverer.getParameterNames (line 233-236) when the advice method's parameter count is less than the minimum required to hold both the returning and throwing bindings. minimumNumberUnboundArgs counts 1 per non-null returningName and 1 per non-null throwingName; if the method has fewer parameters than that, it cannot possibly accept both bindings.
Solutions
- An advice method is either afterReturning or afterThrowing — set only the corresponding binding (returning XOR throwing), not both.
- Ensure the method declares a parameter for each binding (one for returning and/or one for throwing).
- Remove the extraneous returning/throwing attribute that does not apply to this advice type.
Example fix
// before — both returning and throwing set, method has 1 param
<aop:after-returning method="after"
pointcut="execution(* *(..))" returning="r" throwing="ex"/>
public void after(Object r) {} // needs 2 params but has 1
// after — after-returning binds only returning
<aop:after-returning method="after"
pointcut="execution(* *(..))" returning="r"/>
public void after(Object r) {} Defensive patterns
Strategy: validation
Validate before calling
import java.lang.reflect.Method;
// Before configuring, ensure the method has enough params for the bindings you intend.
void assertEnoughParamsForBindings(Method adviceMethod, boolean returning, boolean throwing) {
int needed = (returning ? 1 : 0) + (throwing ? 1 : 0);
if (adviceMethod.getParameterCount() < needed) {
throw new IllegalStateException("method has " + adviceMethod.getParameterCount()
+ " params but needs >= " + needed + " for returning/throwing");
}
} Type guard
boolean hasEnoughParamsForBindings(Method m, boolean returning, boolean throwing) {
int needed = (returning ? 1 : 0) + (throwing ? 1 : 0);
return m.getParameterCount() >= needed;
} Try / catch
try {
advice.getPointcut();
} catch (IllegalStateException ex) {
if (ex.getMessage().contains("returning and throwing variables")) {
// set only returning XOR throwing, and add the matching parameter
} else { throw ex; }
} Prevention
- Set either returning or throwing on an advice, never both.
- Ensure the method declares a parameter for each binding.
- Validate binding configuration against the method signature at startup.
When it happens
Trigger: Configuring an advice method with fewer parameters than the sum of returning + throwing bindings — e.g. a method taking a single Throwable parameter but both returning="r" and throwing="ex" are set. Since an advice can be afterReturning XOR afterThrowing, setting both is itself suspicious, but the discoverer fails when the count is insufficient.
Common situations: Accidentally setting both returning and throwing on the same advice, or an advice method whose signature was trimmed (params removed) without updating the returning/throwing configuration. Common in generic advice-registration code that copies both attributes.
Related errors
- 'argumentNames' property of AbstractAspectJAdvice contains…
- Binding of throwing parameter
- Expecting to find arguments to bind by name in advice, but…
- Failed to bind all argument names
- Advice method [ ] requires arguments to be bound by name…
AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09).
Data as JSON: /api/errors/1fb53de1fb32a46a.
Report an issue: GitHub.
Appendix: source
Thrown at spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java:234
* for this class for details on the algorithm used.
* @param method the target {@link Method}
* @return the parameter names
*/
@Override
public @Nullable String @Nullable [] getParameterNames(Method method) {
this.argumentTypes = method.getParameterTypes();
this.numberOfRemainingUnboundArguments = this.argumentTypes.length;
this.parameterNameBindings = new String[this.numberOfRemainingUnboundArguments];
int minimumNumberUnboundArgs = 0;
if (this.returningName != null) {
minimumNumberUnboundArgs++;
}
if (this.throwingName != null) {
minimumNumberUnboundArgs++;
}
if (this.numberOfRemainingUnboundArguments < minimumNumberUnboundArgs) {
throw new IllegalStateException(
"Not enough arguments in method to satisfy binding of returning and throwing variables");
}
try {
int algorithmicStep = STEP_JOIN_POINT_BINDING;
while (this.numberOfRemainingUnboundArguments > 0 && algorithmicStep < STEP_FINISHED) {
switch (algorithmicStep++) {
case STEP_JOIN_POINT_BINDING -> {
if (!maybeBindThisJoinPoint()) {
maybeBindThisJoinPointStaticPart();
}
}
case STEP_THROWING_BINDING -> maybeBindThrowingVariable();
case STEP_ANNOTATION_BINDING -> maybeBindAnnotationsFromPointcutExpression();
case STEP_RETURNING_BINDING -> maybeBindReturningVariable();
case STEP_PRIMITIVE_ARGS_BINDING -> maybeBindPrimitiveArgsFromPointcutExpression();
case STEP_THIS_TARGET_ARGS_BINDING -> maybeBindThisOrTargetOrArgsFromPointcutExpression();
case STEP_REFERENCE_PCUT_BINDING -> maybeBindReferencePointcutParameter();View on GitHub (pinned to 69bf83ad71)