{"id":"7ace6b6180ba2a12","repo":"spring-projects/spring-framework","slug":"only-afterthrowing-advice-can-be-used-to-bind-a-th","errorCode":null,"errorMessage":"Only afterThrowing advice can be used to bind a thrown exception","messagePattern":"Only afterThrowing advice can be used to bind a thrown exception","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java","lineNumber":326,"sourceCode":"\t\t\t}\n\t\t\tcatch (Throwable ex) {\n\t\t\t\tthrow new IllegalArgumentException(\"Returning name '\" + name +\n\t\t\t\t\t\t\"' is neither a valid argument name nor the fully-qualified \" +\n\t\t\t\t\t\t\"name of a Java type on the classpath. Root cause: \" + ex);\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected Class<?> getDiscoveredReturningType() {\n\t\treturn this.discoveredReturningType;\n\t}\n\n\tprotected @Nullable Type getDiscoveredReturningGenericType() {\n\t\treturn this.discoveredReturningGenericType;\n\t}\n\n\tpublic void setThrowingName(String name) {\n\t\tthrow new UnsupportedOperationException(\"Only afterThrowing advice can be used to bind a thrown exception\");\n\t}\n\n\t/**\n\t * We need to hold the throwing name at this level for argument binding calculations,\n\t * this method allows the afterThrowing advice subclass to set the name.\n\t */\n\tprotected void setThrowingNameNoCheck(String name) {\n\t\t// name could be a variable or a type...\n\t\tif (isVariableName(name)) {\n\t\t\tthis.throwingName = name;\n\t\t}\n\t\telse {\n\t\t\t// assume a type\n\t\t\ttry {\n\t\t\t\tthis.discoveredThrowingType = ClassUtils.forName(name, getAspectClassLoader());\n\t\t\t}\n\t\t\tcatch (Throwable ex) {\n\t\t\t\tthrow new IllegalArgumentException(\"Throwing name '\" + name +","sourceCodeStart":308,"sourceCodeEnd":344,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/e8729d043887bf0d0baf91e062e909b56eb2b708/spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java#L308-L344","documentation":"The base AbstractAspectJAdvice.setThrowingName(String) (line 325-327) is a guard that throws UnsupportedOperationException: only after-throwing advice can bind a thrown exception. AspectJAfterThrowingAdvice overrides this method; any other advice subtype retains the throwing base implementation and rejects the call.","triggerScenarios":"Calling setThrowingName (or configuring a 'throwing' attribute) on AspectJMethodBeforeAdvice, AspectJAfterAdvice, AspectJAfterReturningAdvice, or AspectJAroundAdvice, i.e. putting throwing=\"...\" on <aop:before>, <aop:after>, <aop:after-returning>, or <aop:around>.","commonSituations":"XML/annotation misconfiguration: reusing an after-throwing block as a template and leaving 'throwing' on the now-different advice kind; expecting exception binding on around advice (around should catch via proceed() instead).","solutions":["Place the 'throwing' attribute only on an <aop:after-throwing> element (or @AfterThrowing advice).","Remove 'throwing' from the before/after/after-returning/around element causing the error.","For around advice, capture exceptions via try/catch around pjp.proceed() instead of a throwing binding.","When building advice programmatically, call setThrowingName only on AspectJAfterThrowingAdvice."],"exampleFix":"// before\n@Around(value = \"execution(* svc.*(..))\", throwing = \"ex\")\npublic Object around(ProceedingJoinPoint pjp, Exception ex) { ... }\n// after\n@AfterThrowing(value = \"execution(* svc.*(..))\", throwing = \"ex\")\npublic void onThrow(Exception ex) { ... }","handlingStrategy":"validation","validationCode":"// Only call setThrowingName on the correct advice subtype.\nif (advice instanceof AspectJAfterThrowingAdvice) {\n    advice.setThrowingName(name);\n} else {\n    throw new IllegalStateException(\"throwing binding requires after-throwing advice, got \" + advice.getClass());\n}","typeGuard":"private static boolean supportsThrowing(AbstractAspectJAdvice a) {\n    return a instanceof AspectJAfterThrowingAdvice;\n}","tryCatchPattern":"try {\n    advice.setThrowingName(name);\n} catch (UnsupportedOperationException ex) {\n    throw new IllegalStateException(\n        \"'throwing' is only valid on after-throwing advice; remove it from \" + advice.getClass().getSimpleName(), ex);\n}","preventionTips":["Place 'throwing' only on after-throwing advice (XML element or @AfterThrowing).","For around advice, catch exceptions via proceed() instead of a throwing binding.","When templating advice XML, change advice kind and strip returning/throwing together."],"tags":["spring-aop","aspectj","after-throwing","configuration","misuse"],"analyzedSha":"e8729d043887bf0d0baf91e062e909b56eb2b708","analyzedAt":"2026-08-04T19:07:39.725Z","schemaVersion":2}