spring-projects/spring-framework · error · AmbiguousBindingException

Found candidate reference pointcut variables but only one…

Error message

Found {} candidate reference pointcut variables but only one unbound argument slot

What it means

Thrown when one unbound argument slot remains but the pointcut's reference pointcut expressions yield multiple candidate variable names. Spring cannot choose among the candidates for the single slot.

Solutions

  1. Compile with -parameters to resolve names directly
  2. Reduce the pointcut to a single reference-pointcut binding or add a parameter for each
  3. Restructure the pointcut composition to expose only one binding variable

Example fix

// before
@Before("com.x.Pc1.first(p1) && com.x.Pc2.second(p2)")
public void before(Object single) { ... } // 2 candidates, 1 slot

// after
@Before("com.x.Pc1.first(p1)")
public void before(Object p1) { ... }
Defensive patterns

Strategy: validation

Validate before calling

// If using reference pointcuts that expose bindings, ensure at most one binding variable per unbound slot
// Reference pointcuts are named pointcuts referenced in the expression (not AspectJ keywords).
// Compiling with -parameters makes this check unnecessary.

Try / catch

try {
    discoverer.getParameterNames(adviceMethod);
} catch (AspectJAdviceParameterNameDiscoverer.AmbiguousBindingException ex) {
    // Reduce reference pointcut bindings to one, or add params for each
}

Prevention

When it happens

Trigger: A pointcut referencing multiple shared named pointcuts that each expose a binding variable, with an advice method that has exactly one unbound slot — e.g. @Before("com.x.Pc1.a(p1) && com.x.Pc2.b(p2)") void before(Object single). Only fires when setRaiseExceptions(true).

Common situations: Composed pointcut references with multiple exposed bindings but a single advice parameter, compiled without -parameters.

Related errors


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

Appendix: source

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

				}

			}

			// eat the body
			PointcutBody body = getPointcutBody(tokens, i);
			i += body.numTokensConsumed;

			if (!nonReferencePointcutTokens.contains(toMatch)) {
				// then it could be a reference pointcut
				String varName = maybeExtractVariableName(body.text);
				if (varName != null) {
					varNames.add(varName);
				}
			}
		}

		if (varNames.size() > 1) {
			throw new AmbiguousBindingException("Found " + varNames.size() +
					" candidate reference pointcut 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.
	}

	/**
	 * We've found the start of a binding pointcut at the given index into the
	 * token array. Now we need to extract the pointcut body and return it.
	 */
	private PointcutBody getPointcutBody(String[] tokens, int startIndex) {

View on GitHub (pinned to 69bf83ad71)