spring-projects/spring-framework · error · AmbiguousBindingException

Found potential annotation variable(s) and potential…

Error message

Found {} potential annotation variable(s) and {} potential argument slots

What it means

Thrown by AspectJAdviceParameterNameDiscoverer during annotation-based pointcut binding. The pointcut expression uses annotation-binding designators (@annotation, @this, @target, @within, @withincode, @args in binding form) but the advice method has more than one unbound parameter that is a subtype of Annotation. Spring cannot match which annotation parameter corresponds to which binding.

Solutions

  1. Compile with -parameters so actual parameter names resolve directly without deduction
  2. Restrict the advice method to a single annotation-typed parameter per binding
  3. Split the advice into separate advice methods, each handling one annotation binding

Example fix

// before
@Before("@annotation(a)")
public void before(MyAnnotation a, OtherAnnotation b) { ... } // 2 annotation slots, ambiguous

// after
@Before("@annotation(a)")
public void before(MyAnnotation a) { ... }
Defensive patterns

Strategy: validation

Validate before calling

// Count annotation-typed unbound parameters and warn if >1 with annotation bindings
long annotationParams = Arrays.stream(adviceMethod.getParameterTypes())
    .filter(p -> p != JoinPoint.class && p != ProceedingJoinPoint.class)
    .filter(Annotation.class::isAssignableFrom)
    .count();
if (annotationParams > 1 && pointcutExpr.contains("@annotation") || pointcutExpr.contains("@args")) {
    throw new IllegalStateException("Multiple annotation-typed params with annotation bindings are ambiguous");
}

Try / catch

try {
    discoverer.getParameterNames(adviceMethod);
} catch (AspectJAdviceParameterNameDiscoverer.AmbiguousBindingException ex) {
    // Reduce to one annotation param or split into separate advice methods
}

Prevention

When it happens

Trigger: An advice method with two or more annotation-typed parameters and a pointcut that uses annotation-binding designators — e.g. @Before("@annotation(a)") void before(MyAnnotation a, OtherAnnotation b) where both are unbound annotation-typed params. Only fires when setRaiseExceptions(true).

Common situations: Multiple annotation bindings in a single pointcut combined with multiple annotation-typed advice parameters, compiled without -parameters.

Related errors


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

Appendix: source

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

			else if (tokens[i].startsWith("@args(") || tokens[i].equals("@args")) {
				PointcutBody body = getPointcutBody(tokens, i);
				i += body.numTokensConsumed;
				maybeExtractVariableNamesFromArgs(body.text, varNames);
			}
		}

		bindAnnotationsFromVarNames(varNames);
	}

	/**
	 * Match the given list of extracted variable names to argument slots.
	 */
	private void bindAnnotationsFromVarNames(List<String> varNames) {
		if (!varNames.isEmpty()) {
			// we have work to do...
			int numAnnotationSlots = countNumberOfUnboundAnnotationArguments();
			if (numAnnotationSlots > 1) {
				throw new AmbiguousBindingException("Found " + varNames.size() +
						" potential annotation variable(s) and " +
						numAnnotationSlots + " potential argument slots");
			}
			else if (numAnnotationSlots == 1) {
				if (varNames.size() == 1) {
					// it's a match
					findAndBind(Annotation.class, varNames.get(0));
				}
				else {
					// multiple candidate vars, but only one slot
					throw new IllegalArgumentException("Found " + varNames.size() +
							" candidate annotation binding variables" +
							" but only one potential argument binding slot");
				}
			}
			else {
				// no slots so presume those candidate vars were actually type names
			}

View on GitHub (pinned to 69bf83ad71)