spring-projects/spring-framework · error · AmbiguousBindingException

Still unbound args at reference pointcut binding stage…

Error message

Still {} unbound args at reference pointcut binding stage, with no way to determine between them

What it means

Thrown by AspectJAdviceParameterNameDiscoverer at the reference pointcut binding stage (the final deduction stage) when more than one argument remains unbound. A reference pointcut is a named pointcut referenced in the expression (e.g. com.xyz.MyPointcuts.myPc()); the algorithm can only bind one slot from it.

Solutions

  1. Compile with -parameters so real parameter names resolve without deduction
  2. Add bindings for remaining parameters via other designators (args, this, target, annotation) earlier in the algorithm
  3. Reduce the advice method parameters so at most one is unbound by this stage

Example fix

// before — 2 unbound params at reference pointcut stage
@Before("com.example.CommonPointcuts.businessOp(p)")
public void before(Object p, Object extra) { ... }

// after
@Before("com.example.CommonPointcuts.businessOp(p) && args(extra)")
public void before(Object p, Object extra) { ... }
Defensive patterns

Strategy: validation

Validate before calling

// This is the last deduction stage; if >1 param is still unbound, deduction cannot succeed.
// Best prevention: compile with -parameters so the discoverer is never consulted.
if (!compiledWithParameters) {
    int unbound = adviceMethod.getParameterCount();
    // subtract JoinPoint, returning, throwing, all bindings you know about
    if (unbound > 1) {
        logger.warn("Advice may fail parameter deduction at reference pointcut stage; compile with -parameters");
    }
}

Try / catch

try {
    discoverer.getParameterNames(adviceMethod);
} catch (AspectJAdviceParameterNameDiscoverer.AmbiguousBindingException ex) {
    // Add more bindings or compile with -parameters
}

Prevention

When it happens

Trigger: An advice method with two or more remaining unbound parameters whose pointcut references a named pointcut exposing a binding variable — e.g. @Before("com.x.MyAspect.myPc(p)") void before(Object p, Object other). Only fires when setRaiseExceptions(true).

Common situations: Complex composed pointcuts referencing shared pointcut definitions, with advice methods that have extra unmatched parameters, compiled without -parameters.

Related errors


AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09). Data as JSON: /api/errors/3d08ce60bf228d77. Report an issue: GitHub.

Appendix: source

Thrown at spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java:533

		if (varNames.size() > 1) {
			throw new AmbiguousBindingException("Found " + varNames.size() +
					" candidate this(), target(), or args() variables but only one unbound argument slot");
		}
		else if (varNames.size() == 1) {
			for (int j = 0; j < this.parameterNameBindings.length; j++) {
				if (isUnbound(j)) {
					bindParameterName(j, varNames.get(0));
					break;
				}
			}
		}
		// else varNames.size must be 0 and we have nothing to bind.
	}

	private void maybeBindReferencePointcutParameter() {
		if (this.numberOfRemainingUnboundArguments > 1) {
			throw new AmbiguousBindingException("Still " + this.numberOfRemainingUnboundArguments +
					" unbound args at reference pointcut binding stage, with no way to determine between them");
		}

		List<String> varNames = new ArrayList<>();
		String[] tokens = StringUtils.tokenizeToStringArray(this.pointcutExpression, " ");
		for (int i = 0; i < tokens.length; i++) {
			String toMatch = tokens[i];
			if (toMatch.startsWith("!")) {
				toMatch = toMatch.substring(1);
			}
			int firstParenIndex = toMatch.indexOf('(');
			if (firstParenIndex != -1) {
				toMatch = toMatch.substring(0, firstParenIndex);
			}
			else {
				if (tokens.length < i + 2) {
					// no "(" and nothing following
					continue;

View on GitHub (pinned to 69bf83ad71)