spring-projects/spring-framework · error · AopConfigException
Invalid afterThrowing signature: four arguments must be…
Error message
Invalid afterThrowing signature: four arguments must be Method, Object[], target, throwable: {} What it means
Thrown as AopConfigException by ThrowsAdviceInterceptor's constructor when an afterThrowing method has four parameters but they do not match (Method, Object[], target, ThrowableSubclass). The check at lines 95-96 requires paramTypes[0]==Method.class, paramTypes[1]==Object[].class, paramTypes[2] != Throwable.class (target may be any non-Throwable type, normally Object), and paramTypes[3] a Throwable subclass.
Solutions
- Match the canonical signature exactly: 'public void afterThrowing(Method m, Object[] args, Object target, SomeThrowable ex)'.
- If you do not need the context, drop to the single-Throwable-argument form.
- Double-check param order: Method first, Object[] args second, target third, Throwable fourth.
Example fix
// before
public void afterThrowing(Method m, Object args, Object target, Exception ex) { ... } // Object not Object[]
// after
public void afterThrowing(Method m, Object[] args, Object target, Exception ex) { ... } Defensive patterns
Strategy: validation
Validate before calling
for (Method m : advice.getClass().getMethods()) {
if (m.getName().equals("afterThrowing") && m.getParameterCount() == 4) {
Class<?>[] p = m.getParameterTypes();
if (!Method.class.equals(p[0]) || !Object[].class.equals(p[1])
|| Throwable.class.equals(p[2]) || !Throwable.class.isAssignableFrom(p[3])) {
throw new IllegalStateException("Bad 4-arg afterThrowing: " + m);
}
}
} Type guard
static boolean validFourArgThrows(Method m) {
if (m.getParameterCount() != 4) return false;
Class<?>[] p = m.getParameterTypes();
return Method.class.equals(p[0]) && Object[].class.equals(p[1])
&& !Throwable.class.equals(p[2]) && Throwable.class.isAssignableFrom(p[3]);
} Try / catch
try { new ThrowsAdviceInterceptor(advice); }
catch (AopConfigException e) {
if (e.getMessage().contains("four arguments must be")) { /* fix to (Method, Object[], Object, Throwable) */ }
throw e;
} Prevention
- Use exactly (Method, Object[], Object, ThrowableSubclass).
- Remember the target slot cannot be exactly Throwable.
When it happens
Trigger: Defining 'afterThrowing(Method, Object, Object, Exception)' (second param Object not Object[]), or 'afterThrowing(Method, Object[], Throwable, Exception)' (target position is Throwable), or any four-arg variant with the wrong types.
Common situations: Mistakenly using Object instead of Object[] for the args parameter; reordering arguments; using Throwable as the target parameter type.
Related errors
- Invalid afterThrowing signature: single argument must be a…
- Only one afterThrowing method per specific Throwable…
- Unsupported afterThrowing signature: single throwable…
- 'argumentNames' property of AbstractAspectJAdvice contains…
- At least one handler method must be found in class
AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09).
Data as JSON: /api/errors/2766530d43837311.
Report an issue: GitHub.
Appendix: source
Thrown at spring-aop/src/main/java/org/springframework/aop/framework/adapter/ThrowsAdviceInterceptor.java:97
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...
Method existingMethod = this.exceptionHandlerMap.put(throwableParam, method);
if (existingMethod != null) {
throw new AopConfigException("Only one afterThrowing method per specific Throwable subclass " +
"allowed: " + method + " / " + existingMethod);
}
if (logger.isDebugEnabled()) {
logger.debug("Found exception handler method on throws advice: " + method);
}
}View on GitHub (pinned to 69bf83ad71)