spring-projects/spring-framework · error · AmbiguousBindingException

Found {} candidate this(), target(), or args() variables but

Error message

Found {} candidate this(), target(), or args() variables but only one unbound argument slot

What it means

Thrown when the pointcut expression contains multiple candidate this/target/args binding variables but there is only one unbound argument slot. Spring cannot decide which variable name to bind. Only surfaces when raiseExceptions=true.

Source

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

				}
			}
			else if (tokens[i].equals("args") || tokens[i].startsWith("args(")) {
				PointcutBody body = getPointcutBody(tokens, i);
				i += body.numTokensConsumed;
				List<String> candidateVarNames = new ArrayList<>();
				maybeExtractVariableNamesFromArgs(body.text, candidateVarNames);
				// we may have found some var names that were bound in previous primitive args binding step,
				// filter them out...
				for (String varName : candidateVarNames) {
					if (!alreadyBound(varName)) {
						varNames.add(varName);
					}
				}
			}
		}

		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");
		}

View on GitHub (pinned to e8729d0438)

Solutions

  1. Make the advice method parameter count match the number of bound variables in the pointcut.
  2. Remove extra this/target/args binding clauses from the pointcut.
  3. Compile with -parameters and ensure each bound variable has a corresponding parameter.

Example fix

// before
@Before("target(t) && args(a)")
public void before(Object t) { ... }

// after
@Before("target(t) && args(a)")
public void before(Object t, Object a) { ... }
Defensive patterns

Strategy: validation

Validate before calling

// Match this/target/args binding var count to unbound param count:
int vars = extractBindingVars(this_target_args, pointcutExpression).size();
int unbound = countUnboundParams(adviceMethod);
assert vars <= unbound && (vars == 0 || unbound == 1);

Prevention

When it happens

Trigger: A pointcut like 'target(t) && args(a, b)' yielding two candidate names while only one parameter remains unbound at this stage.

Common situations: Pointcuts that bind multiple variables via this/target/args but the advice method has fewer corresponding parameters; refactor mismatches.

Related errors


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