{"id":"80b32b2cc638b7ee","repo":"spring-projects/spring-framework","slug":"invalid-afterthrowing-signature-single-argument-m","errorCode":null,"errorMessage":"Invalid afterThrowing signature: single argument must be a Throwable subclass","messagePattern":"Invalid afterThrowing signature: single argument must be a Throwable subclass","errorType":"exception","errorClass":"AopConfigException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/framework/adapter/ThrowsAdviceInterceptor.java","lineNumber":88,"sourceCode":"\n\t/**\n\t * Create a new ThrowsAdviceInterceptor for the given ThrowsAdvice.\n\t * @param throwsAdvice the advice object that defines the exception handler methods\n\t * (usually a {@link org.springframework.aop.ThrowsAdvice} implementation)\n\t */\n\tpublic ThrowsAdviceInterceptor(Object throwsAdvice) {\n\t\tAssert.notNull(throwsAdvice, \"Advice must not be null\");\n\t\tthis.throwsAdvice = throwsAdvice;\n\n\t\tMethod[] methods = throwsAdvice.getClass().getMethods();\n\t\tfor (Method method : methods) {\n\t\t\tif (method.getName().equals(AFTER_THROWING)) {\n\t\t\t\tClass<?> throwableParam = null;\n\t\t\t\tif (method.getParameterCount() == 1) {\n\t\t\t\t\t// just a Throwable parameter\n\t\t\t\t\tthrowableParam = method.getParameterTypes()[0];\n\t\t\t\t\tif (!Throwable.class.isAssignableFrom(throwableParam)) {\n\t\t\t\t\t\tthrow new AopConfigException(\"Invalid afterThrowing signature: \" +\n\t\t\t\t\t\t\t\t\"single argument must be a Throwable subclass\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (method.getParameterCount() == 4) {\n\t\t\t\t\t// Method, Object[], target, throwable\n\t\t\t\t\tClass<?>[] paramTypes = method.getParameterTypes();\n\t\t\t\t\tif (!Method.class.equals(paramTypes[0]) || !Object[].class.equals(paramTypes[1]) ||\n\t\t\t\t\t\t\tThrowable.class.equals(paramTypes[2]) || !Throwable.class.isAssignableFrom(paramTypes[3])) {\n\t\t\t\t\t\tthrow new AopConfigException(\"Invalid afterThrowing signature: \" +\n\t\t\t\t\t\t\t\t\"four arguments must be Method, Object[], target, throwable: \" + method);\n\t\t\t\t\t}\n\t\t\t\t\tthrowableParam = paramTypes[3];\n\t\t\t\t}\n\t\t\t\tif (throwableParam == null) {\n\t\t\t\t\tthrow new AopConfigException(\"Unsupported afterThrowing signature: single throwable argument \" +\n\t\t\t\t\t\t\t\"or four arguments Method, Object[], target, throwable expected: \" + method);\n\t\t\t\t}\n\t\t\t\t// An exception handler to register...","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/e8729d043887bf0d0baf91e062e909b56eb2b708/spring-aop/src/main/java/org/springframework/aop/framework/adapter/ThrowsAdviceInterceptor.java#L70-L106","documentation":"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.","triggerScenarios":"Defining 'public void afterThrowing(String s)' or 'afterThrowing(Integer i)' on a ThrowsAdvice implementation; accidentally overloading afterThrowing with a non-throwable single arg.","commonSituations":"Copy-paste from a before/afterReturning handler signature; misunderstanding the ThrowsAdvice contract; auto-completed a wrong parameter type.","solutions":["Change the single-parameter afterThrowing method to take a Throwable (or a subclass like Exception).","If you intended a 4-arg handler, use the full signature: Method, Object[], Object, Throwable.","Remove the invalid overload so only compliant signatures remain."],"exampleFix":"// before\npublic void afterThrowing(String msg) { ... }\n\n// after\npublic void afterThrowing(Exception ex) { ... }","handlingStrategy":"validation","validationCode":"for (Method m : advice.getClass().getMethods()) {\n    if (m.getName().equals(\"afterThrowing\") && m.getParameterCount() == 1) {\n        Class<?> p = m.getParameterTypes()[0];\n        if (!Throwable.class.isAssignableFrom(p)) {\n            throw new IllegalStateException(\"afterThrowing single arg must be Throwable: \" + m);\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Type the single afterThrowing parameter as Throwable or a subclass (Exception, IOException).","Avoid overloading afterThrowing with non-throwable single args.","Run a quick reflection smoke test on ThrowsAdvice classes at startup."],"tags":["aop","throws-advice","signature","configuration"],"analyzedSha":"e8729d043887bf0d0baf91e062e909b56eb2b708","analyzedAt":"2026-08-04T19:07:39.725Z","schemaVersion":2}