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

  1. Compile with -parameters so primitive parameter names are available.
  2. Reduce to a single unbound primitive parameter by binding others via explicit args() position or removing them.
  3. 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

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


AI-assisted analysis of spring-projects/spring-framework@e8729d0438 (2026-08-04). Data as JSON: /data/errors/65fbc6af771a55ce.json. Report an issue: GitHub.