spring-projects/spring-framework · error · AmbiguousBindingException
Found unbound primitive arguments with no way to…
Error message
Found {} unbound primitive arguments with no way to distinguish between them. What it means
Thrown when two or more unbound arguments of primitive types (int, long, boolean, etc.) remain at the primitive-args binding stage. Primitive arguments can only be bound via args(), and when multiple primitives share the same type (e.g., two ints), the algorithm cannot distinguish between them by type alone.
Solutions
- Compile with -parameters so each primitive parameter name resolves directly from bytecode
- Use different primitive types for each parameter if the method signature allows (int vs long vs double)
- Reduce to a single primitive parameter
Example fix
// before
@Before("execution(* *(int, int)) && args(x, y)")
public void before(int x, int y) { ... } // 2 unbound primitives, ambiguous
// after — compile with -parameters so names resolve directly
// Or use boxable distinct types:
@Before("execution(* *(int, long)) && args(x, y)")
public void before(int x, long y) { ... } Defensive patterns
Strategy: validation
Validate before calling
// Count unbound primitive params; warn if >1 since they can't be distinguished by type
long primitiveParams = Arrays.stream(adviceMethod.getParameterTypes())
.filter(Class::isPrimitive).count();
if (primitiveParams > 1 && !compiledWithParameters) {
throw new IllegalStateException(
"Multiple primitive params (" + primitiveParams + ") are ambiguous without -parameters");
} Try / catch
try {
discoverer.getParameterNames(adviceMethod);
} catch (AspectJAdviceParameterNameDiscoverer.AmbiguousBindingException ex) {
// Use -parameters, or use distinct primitive types, or reduce to one primitive param
} Prevention
- Compile with — the definitive fix for primitive arg ambiguity
- Use distinct primitive types (int vs long vs double) for each parameter so they are type-distinguishable
- Avoid binding more than one same-typed primitive parameter in a single advice method
When it happens
Trigger: An advice method with two same-typed primitive parameters like void before(int x, int y) where the pointcut uses args(). Both are int and thus indistinguishable by type. Only fires when setRaiseExceptions(true).
Common situations: Advice methods binding multiple same-typed primitive arguments, compiled without -parameters.
Related errors
- Found candidate variable names but only one candidate…
- 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/65fbc6af771a55ce.
Report an issue: GitHub.
Appendix: 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 69bf83ad71)