spring-projects/spring-framework · error · IllegalStateException

Throwing argument name

Error message

Throwing argument name '{}' was not bound in advice arguments

What it means

Thrown by bindExplicitArguments (line 497-501) when throwingName is set but does not appear as a key in the computed argumentBindings map. The throwing name must match one of the advice method's parameter names so Spring knows which slot receives the thrown exception. A mismatch means the configured 'throwing' cannot be matched to a parameter.

Solutions

  1. Ensure the throwing name exactly matches the advice method's Throwable parameter name.
  2. Compile with -parameters so the real parameter name is discovered and matches throwing.
  3. If using arg-names, confirm it includes the throwing name.
  4. Align XML 'throwing' with the @AfterThrowing(throwing=) value and the method signature.

Example fix

// before — throwing name does not match the parameter
@AfterThrowing(pointcut="execution(* svc.*(..))", throwing="ex")
public void onError(RuntimeException error) { ... }

// after — names agree
@AfterThrowing(pointcut="execution(* svc.*(..))", throwing="error")
public void onError(RuntimeException error) { ... }
Defensive patterns

Strategy: validation

Validate before calling

import java.lang.reflect.Method;
import java.util.Arrays;

void assertThrowingNameBound(Method adviceMethod, String throwingName, String[] discoveredNames) {
    String[] names = discoveredNames != null ? discoveredNames
        : new org.springframework.core.DefaultParameterNameDiscoverer().getParameterNames(adviceMethod);
    if (names == null || !Arrays.asList(names).contains(throwingName)) {
        throw new IllegalStateException("throwing '" + throwingName + "' not found among params " + Arrays.toString(names));
    }
}

Type guard

boolean throwingNameMatchesParam(Method m, String throwingName) {
    String[] names = new org.springframework.core.DefaultParameterNameDiscoverer().getParameterNames(m);
    return names != null && java.util.Arrays.asList(names).contains(throwingName);
}

Try / catch

try {
    advice.getPointcut();
} catch (IllegalStateException ex) {
    if (ex.getMessage().contains("Throwing argument name") && ex.getMessage().contains("not bound")) {
        // align the throwing attribute with the actual parameter name
    } else { throw ex; }
}

Prevention

When it happens

Trigger: Configuring throwing="ex" but the advice method's exception parameter is named differently (e.g. 'error'), or parameter discovery returned a name that does not equal throwing. Common when the parameter name and throwing attribute drift apart.

Common situations: Renaming an advice parameter without updating the throwing attribute (or vice versa), compiling without -parameters so discovered names diverge, or XML/annotation mismatch after refactoring.

Related errors


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

Appendix: source

Thrown at spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java:499

			this.argumentBindings.put(this.argumentNames[i], i);
		}

		// Check that returning and throwing were in the argument names list if
		// specified, and find the discovered argument types.
		if (this.returningName != null) {
			if (!this.argumentBindings.containsKey(this.returningName)) {
				throw new IllegalStateException("Returning argument name '" + this.returningName +
						"' was not bound in advice arguments");
			}
			else {
				Integer index = this.argumentBindings.get(this.returningName);
				this.discoveredReturningType = this.aspectJAdviceMethod.getParameterTypes()[index];
				this.discoveredReturningGenericType = this.aspectJAdviceMethod.getGenericParameterTypes()[index];
			}
		}
		if (this.throwingName != null) {
			if (!this.argumentBindings.containsKey(this.throwingName)) {
				throw new IllegalStateException("Throwing argument name '" + this.throwingName +
						"' was not bound in advice arguments");
			}
			else {
				Integer index = this.argumentBindings.get(this.throwingName);
				this.discoveredThrowingType = this.aspectJAdviceMethod.getParameterTypes()[index];
			}
		}

		// configure the pointcut expression accordingly.
		configurePointcutParameters(this.argumentNames, argumentIndexOffset);
	}

	/**
	 * All parameters from argumentIndexOffset onwards are candidates for
	 * pointcut parameters - but returning and throwing vars are handled differently
	 * and must be removed from the list if present.
	 */
	private void configurePointcutParameters(String[] argumentNames, int argumentIndexOffset) {

View on GitHub (pinned to 69bf83ad71)