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

  1. Compile with -parameters so each primitive parameter name resolves directly from bytecode
  2. Use different primitive types for each parameter if the method signature allows (int vs long vs double)
  3. 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

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


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)