spring-projects/spring-framework · error · AmbiguousBindingException
Found candidate this(), target(), or args() variables but…
Error message
Found {} candidate this(), target(), or args() variables but only one unbound argument slot What it means
Thrown when exactly one unbound argument slot remains but the pointcut's this()/target()/args() expressions yield multiple candidate variable names. Spring cannot pick which candidate to bind to the single remaining slot.
Solutions
- Compile with -parameters to resolve parameter names directly
- Reduce the pointcut to a single binding designator matching the single remaining parameter
- Add the missing parameter to the advice method so each candidate variable has its own slot
Example fix
// before
@Before("target(t) && args(a)")
public void before(Object t) { ... } // 2 candidates, 1 slot
// after
@Before("target(t)")
public void before(Object t) { ... } Defensive patterns
Strategy: validation
Validate before calling
// If only one param slot is unbound, ensure the pointcut has at most one of this()/target()/args() binding
long bindingDesignators = Arrays.stream(new String[]{"this(","target(","args("})
.filter(pointcutExpr::contains).count();
int unbound = /* computed as in error 23 */ 1;
if (unbound == 1 && bindingDesignators > 1) {
throw new IllegalStateException("Multiple this()/target()/args() bindings but only one unbound slot");
} Try / catch
try {
discoverer.getParameterNames(adviceMethod);
} catch (AspectJAdviceParameterNameDiscoverer.AmbiguousBindingException ex) {
// Reduce binding designators to one, or add params for each
} Prevention
- Compile with -parameters
- Match the number of this()/target()/args() binding variables to the number of unbound advice parameters
When it happens
Trigger: A pointcut like target(t) && args(a) with an advice method that has exactly one unbound parameter — e.g. void before(Object t). The algorithm finds two candidate variable names (t and a) but only one slot. Only fires when setRaiseExceptions(true).
Common situations: Multiple binding designators in a pointcut but the advice takes fewer parameters, compiled without -parameters.
Related errors
- Still unbound args at this()/target()/args() binding stage…
- Binding of returning parameter
- Found candidate annotation binding variables but only one…
- Found candidate reference pointcut variables but only one…
- Found candidate variable names but only one candidate…
AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09).
Data as JSON: /api/errors/1e929e7797f0e265.
Report an issue: GitHub.
Appendix: source
Thrown at spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java:517
}
}
else if (tokens[i].equals("args") || tokens[i].startsWith("args(")) {
PointcutBody body = getPointcutBody(tokens, i);
i += body.numTokensConsumed;
List<String> candidateVarNames = new ArrayList<>();
maybeExtractVariableNamesFromArgs(body.text, candidateVarNames);
// we may have found some var names that were bound in previous primitive args binding step,
// filter them out...
for (String varName : candidateVarNames) {
if (!alreadyBound(varName)) {
varNames.add(varName);
}
}
}
}
if (varNames.size() > 1) {
throw new AmbiguousBindingException("Found " + varNames.size() +
" candidate this(), target(), or args() variables but only one unbound argument slot");
}
else if (varNames.size() == 1) {
for (int j = 0; j < this.parameterNameBindings.length; j++) {
if (isUnbound(j)) {
bindParameterName(j, varNames.get(0));
break;
}
}
}
// else varNames.size must be 0 and we have nothing to bind.
}
private void maybeBindReferencePointcutParameter() {
if (this.numberOfRemainingUnboundArguments > 1) {
throw new AmbiguousBindingException("Still " + this.numberOfRemainingUnboundArguments +
" unbound args at reference pointcut binding stage, with no way to determine between them");
}View on GitHub (pinned to 69bf83ad71)