spring-projects/spring-framework · error · IllegalStateException

Binding of throwing parameter '{}' could not be completed as

Error message

Binding of throwing parameter '{}' could not be completed as no available arguments are a subtype of Throwable

What it means

Thrown by maybeBindThrowingVariable (line 350-353) when throwingName is set but no unbound advice parameter is a subtype of Throwable. The throwing binding requires a Throwable-typed parameter to receive the exception; if none exists, binding is impossible.

Source

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

		// So there is binding work to do...
		int throwableIndex = -1;
		for (int i = 0; i < this.argumentTypes.length; i++) {
			if (isUnbound(i) && isSubtypeOf(Throwable.class, i)) {
				if (throwableIndex == -1) {
					throwableIndex = i;
				}
				else {
					// Second candidate we've found - ambiguous binding
					throw new AmbiguousBindingException("Binding of throwing parameter '" +
							this.throwingName + "' is ambiguous: could be bound to argument " +
							throwableIndex + " or " + i);
				}
			}
		}

		if (throwableIndex == -1) {
			throw new IllegalStateException("Binding of throwing parameter '" + this.throwingName +
					"' could not be completed as no available arguments are a subtype of Throwable");
		}
		else {
			bindParameterName(throwableIndex, this.throwingName);
		}
	}

	/**
	 * If a returning variable was specified and there is only one choice remaining, bind it.
	 */
	private void maybeBindReturningVariable() {
		if (this.numberOfRemainingUnboundArguments == 0) {
			throw new IllegalStateException(
					"Algorithm assumes that there must be at least one unbound parameter on entry to this method");
		}

		if (this.returningName != null) {
			if (this.numberOfRemainingUnboundArguments > 1) {

View on GitHub (pinned to e8729d0438)

Solutions

  1. Add a Throwable (or specific exception subtype) parameter to the advice method that matches the throwing name.
  2. Compile with -parameters and ensure a parameter is named exactly as the throwing attribute, with a Throwable type.
  3. Remove the throwing attribute if you do not need to bind the exception.

Example fix

// before
@AfterThrowing(value = "...", throwing = "ex")
public void onThrow(JoinPoint jp) { ... } // no Throwable param
// after
@AfterThrowing(value = "...", throwing = "ex")
public void onThrow(JoinPoint jp, Throwable ex) { ... }
Defensive patterns

Strategy: validation

Validate before calling

// Before wiring after-throwing, ensure a Throwable param exists when throwing is set.
boolean hasThrowableParam = Arrays.stream(adviceMethod.getParameterTypes())
    .anyMatch(Throwable.class::isAssignableFrom);
if (throwingName != null && !hasThrowableParam) {
    throw new IllegalStateException("throwing='" + throwingName
        + "' set but " + adviceMethod + " has no Throwable parameter");
}

Prevention

When it happens

Trigger: Configuring after-throwing with throwing='ex' but the advice method has no parameter whose type is a Throwable (e.g. all params are business types or a JoinPoint), and parameter names are unavailable so type-based matching is attempted.

Common situations: Forgetting to add the exception parameter to the advice method; declaring the throwing attribute but the method only has a JoinPoint/business params; renaming/removing the exception parameter without dropping the throwing attribute.

Related errors


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