spring-projects/spring-framework · error · AopConfigException

Invalid afterThrowing signature: single argument must be a T

Error message

Invalid afterThrowing signature: single argument must be a Throwable subclass

What it means

ThrowsAdviceInterceptor scans public methods named 'afterThrowing' on the advice object. The single-argument variant must take a Throwable subclass. If the lone parameter is not assignable to Throwable, AopConfigException is thrown because the handler could never receive an exception.

Source

Thrown at spring-aop/src/main/java/org/springframework/aop/framework/adapter/ThrowsAdviceInterceptor.java:88

	/**
	 * Create a new ThrowsAdviceInterceptor for the given ThrowsAdvice.
	 * @param throwsAdvice the advice object that defines the exception handler methods
	 * (usually a {@link org.springframework.aop.ThrowsAdvice} implementation)
	 */
	public ThrowsAdviceInterceptor(Object throwsAdvice) {
		Assert.notNull(throwsAdvice, "Advice must not be null");
		this.throwsAdvice = throwsAdvice;

		Method[] methods = throwsAdvice.getClass().getMethods();
		for (Method method : methods) {
			if (method.getName().equals(AFTER_THROWING)) {
				Class<?> throwableParam = null;
				if (method.getParameterCount() == 1) {
					// just a Throwable parameter
					throwableParam = method.getParameterTypes()[0];
					if (!Throwable.class.isAssignableFrom(throwableParam)) {
						throw new AopConfigException("Invalid afterThrowing signature: " +
								"single argument must be a Throwable subclass");
					}
				}
				else if (method.getParameterCount() == 4) {
					// Method, Object[], target, throwable
					Class<?>[] paramTypes = method.getParameterTypes();
					if (!Method.class.equals(paramTypes[0]) || !Object[].class.equals(paramTypes[1]) ||
							Throwable.class.equals(paramTypes[2]) || !Throwable.class.isAssignableFrom(paramTypes[3])) {
						throw new AopConfigException("Invalid afterThrowing signature: " +
								"four arguments must be Method, Object[], target, throwable: " + method);
					}
					throwableParam = paramTypes[3];
				}
				if (throwableParam == null) {
					throw new AopConfigException("Unsupported afterThrowing signature: single throwable argument " +
							"or four arguments Method, Object[], target, throwable expected: " + method);
				}
				// An exception handler to register...

View on GitHub (pinned to e8729d0438)

Solutions

  1. Change the single-parameter afterThrowing method to take a Throwable (or a subclass like Exception).
  2. If you intended a 4-arg handler, use the full signature: Method, Object[], Object, Throwable.
  3. Remove the invalid overload so only compliant signatures remain.

Example fix

// before
public void afterThrowing(String msg) { ... }

// after
public void afterThrowing(Exception ex) { ... }
Defensive patterns

Strategy: validation

Validate before calling

for (Method m : advice.getClass().getMethods()) {
    if (m.getName().equals("afterThrowing") && m.getParameterCount() == 1) {
        Class<?> p = m.getParameterTypes()[0];
        if (!Throwable.class.isAssignableFrom(p)) {
            throw new IllegalStateException("afterThrowing single arg must be Throwable: " + m);
        }
    }
}

Prevention

When it happens

Trigger: Defining 'public void afterThrowing(String s)' or 'afterThrowing(Integer i)' on a ThrowsAdvice implementation; accidentally overloading afterThrowing with a non-throwable single arg.

Common situations: Copy-paste from a before/afterReturning handler signature; misunderstanding the ThrowsAdvice contract; auto-completed a wrong parameter type.

Related errors


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