spring-projects/spring-framework · error · AmbiguousBindingException
Found {} unbound primitive arguments with no way to distingu
Error message
Found {} unbound primitive arguments with no way to distinguish between them. What it means
Thrown when more than one unbound primitive-typed argument remains at the primitive-args binding stage. Since multiple primitive args cannot be told apart without compiled names, Spring refuses to guess. Only surfaces when raiseExceptions=true.
Source
Thrown at spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java:644
sb.append(toAppend);
sb.append(' ');
currentIndex++;
numTokensConsumed++;
}
}
// We looked and failed...
return new PointcutBody(numTokensConsumed, null);
}
/**
* Match up args against unbound arguments of primitive types.
*/
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) {View on GitHub (pinned to e8729d0438)
Solutions
- Compile with -parameters so primitive parameter names are available.
- Reduce to a single unbound primitive parameter by binding others via explicit args() position or removing them.
- Wrap primitives or use a single composite parameter.
Example fix
// before
@Before("execution(* com.acme.*.*(int,int)) && args(a,b)")
public void before(int a, int b) { ... }
// after
// compile with -parameters, OR bind a single primitive and pass the rest explicitly:
@Before("execution(* com.acme.*.*(int,int)) && args(a,*)")
public void before(int a) { ... } Defensive patterns
Strategy: validation
Validate before calling
// Ensure at most one unbound primitive param:
long unboundPrimitives = Arrays.stream(method.getParameterTypes())
.filter(Class::isPrimitive).count();
assert unboundPrimitives <= 1; Prevention
- Compile with -parameters.
- Bind all but one primitive explicitly via args().
- Avoid advice methods binding multiple primitives without compiled names.
When it happens
Trigger: An advice method with two or more primitive parameters (int, long, boolean, etc.) that are not bound by earlier stages, reached the primitive args() binding step.
Common situations: Advice methods monitoring methods with multiple primitive arguments bound via args() without -parameters; refactor adding a second primitive parameter.
Related errors
- Found {} candidate variable names but only one candidate bin
- Binding of returning parameter '{}' is ambiguous: there are
- Found {} potential annotation variable(s) and {} potential a
- Found {} candidate annotation binding variables but only one
- Still {} unbound args at this()/target()/args() binding stag
AI-assisted analysis of spring-projects/spring-framework@e8729d0438 (2026-08-04).
Data as JSON: /data/errors/65fbc6af771a55ce.json.
Report an issue: GitHub.