spring-projects/spring-framework · error · AmbiguousBindingException
Found candidate variable names but only one candidate…
Error message
Found {} candidate variable names but only one candidate binding slot when matching primitive args What it means
Thrown when exactly one primitive argument slot remains but the args() expression in the pointcut yields multiple candidate variable names. Spring cannot determine which candidate binds to the single primitive slot.
Solutions
- Compile with -parameters to resolve names directly
- Reduce args() in the pointcut to a single binding variable
- Add the matching number of parameters to the advice method
Example fix
// before
@Before("args(a, b)")
public void before(int a) { ... } // 2 candidates, 1 primitive slot
// after
@Before("args(a)")
public void before(int a) { ... } Defensive patterns
Strategy: validation
Validate before calling
// If the advice has exactly one primitive param, ensure args() in the pointcut has at most one binding variable
int primitiveSlots = (int) Arrays.stream(adviceMethod.getParameterTypes())
.filter(Class::isPrimitive).count();
if (primitiveSlots == 1 && pointcutExpr.contains("args(")) {
// Count binding variables in args(...) — if >1, this will throw
logger.warn("Multiple args() binding variables with one primitive slot may be ambiguous");
} Try / catch
try {
discoverer.getParameterNames(adviceMethod);
} catch (AspectJAdviceParameterNameDiscoverer.AmbiguousBindingException ex) {
// Reduce args() to a single binding variable, or add params
} Prevention
- Compile with -parameters
- Match args() binding variable count to the number of primitive advice parameters
When it happens
Trigger: A pointcut like args(a, b) with an advice method that has exactly one primitive parameter — e.g. void before(int a). The algorithm finds two candidate variable names but only one primitive slot. Only fires when setRaiseExceptions(true).
Common situations: Over-specified args() binding with fewer advice parameters than bindings, compiled without -parameters.
Related errors
- Found unbound primitive arguments with no way to…
- Binding of returning parameter
- Found candidate annotation binding variables but only one…
- Found candidate reference pointcut variables but only one…
- Found candidate this(), target(), or args() variables but…
AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09).
Data as JSON: /api/errors/f88a1e975067818e.
Report an issue: GitHub.
Appendix: source
Thrown at spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java:659
private void maybeBindPrimitiveArgsFromPointcutExpression() {
int numUnboundPrimitives = countNumberOfUnboundPrimitiveArguments();
if (numUnboundPrimitives > 1) {
throw new AmbiguousBindingException("Found " + numUnboundPrimitives +
" unbound primitive arguments with no way to distinguish between them.");
}
if (numUnboundPrimitives == 1) {
// Look for arg variable and bind it if we find exactly one...
List<String> varNames = new ArrayList<>();
String[] tokens = StringUtils.tokenizeToStringArray(this.pointcutExpression, " ");
for (int i = 0; i < tokens.length; i++) {
if (tokens[i].equals("args") || tokens[i].startsWith("args(")) {
PointcutBody body = getPointcutBody(tokens, i);
i += body.numTokensConsumed;
maybeExtractVariableNamesFromArgs(body.text, varNames);
}
}
if (varNames.size() > 1) {
throw new AmbiguousBindingException("Found " + varNames.size() +
" candidate variable names but only one candidate binding slot when matching primitive args");
}
else if (varNames.size() == 1) {
// 1 primitive arg, and one candidate...
for (int i = 0; i < this.argumentTypes.length; i++) {
if (isUnbound(i) && this.argumentTypes[i].isPrimitive()) {
bindParameterName(i, varNames.get(0));
break;
}
}
}
}
}
/*
* Return true if the parameter name binding for the given parameter
* index has not yet been assigned.
*/View on GitHub (pinned to 69bf83ad71)