{"id":"f4128ccd26861112","repo":"spring-projects/spring-framework","slug":"binding-of-throwing-parameter-is-ambiguous-c","errorCode":null,"errorMessage":"Binding of throwing parameter '{}' is ambiguous: could be bound to argument {} or {}","messagePattern":"Binding of throwing parameter '(.+?)' is ambiguous: could be bound to argument (.+?) or (.+?)","errorType":"exception","errorClass":"AmbiguousBindingException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java","lineNumber":343,"sourceCode":"\t/**\n\t * If a throwing name was specified and there is exactly one choice remaining\n\t * (argument that is a subtype of Throwable) then bind it.\n\t */\n\tprivate void maybeBindThrowingVariable() {\n\t\tif (this.throwingName == null) {\n\t\t\treturn;\n\t\t}\n\n\t\t// So there is binding work to do...\n\t\tint throwableIndex = -1;\n\t\tfor (int i = 0; i < this.argumentTypes.length; i++) {\n\t\t\tif (isUnbound(i) && isSubtypeOf(Throwable.class, i)) {\n\t\t\t\tif (throwableIndex == -1) {\n\t\t\t\t\tthrowableIndex = i;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Second candidate we've found - ambiguous binding\n\t\t\t\t\tthrow new AmbiguousBindingException(\"Binding of throwing parameter '\" +\n\t\t\t\t\t\t\tthis.throwingName + \"' is ambiguous: could be bound to argument \" +\n\t\t\t\t\t\t\tthrowableIndex + \" or \" + i);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (throwableIndex == -1) {\n\t\t\tthrow new IllegalStateException(\"Binding of throwing parameter '\" + this.throwingName +\n\t\t\t\t\t\"' could not be completed as no available arguments are a subtype of Throwable\");\n\t\t}\n\t\telse {\n\t\t\tbindParameterName(throwableIndex, this.throwingName);\n\t\t}\n\t}\n\n\t/**\n\t * If a returning variable was specified and there is only one choice remaining, bind it.\n\t */","sourceCodeStart":325,"sourceCodeEnd":361,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/e8729d043887bf0d0baf91e062e909b56eb2b708/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java#L325-L361","documentation":"Thrown by maybeBindThrowingVariable (line 342-346) as an AmbiguousBindingException when throwingName is set and there are two or more unbound advice parameters that are subtypes of Throwable. The heuristic cannot decide which one binds the thrown exception, so it refuses rather than guess.","triggerScenarios":"An after-throwing advice method declares multiple Throwable subtypes (e.g. RuntimeException and Exception) and throwing='ex' is set, while parameter names aren't available (compiled without -parameters) so the discoverer falls back to type-based matching and finds multiple candidates.","commonSituations":"Advice methods with more than one exception-typed parameter; mixing a generic Throwable param with a specific exception type; bytecode without parameter names forcing type-based binding.","solutions":["Compile with -parameters so the discoverer binds by the actual parameter name matching the throwing attribute.","Supply explicit arg-names so the throwing name maps to the intended parameter.","Reduce the advice method to a single Throwable-typed parameter."],"exampleFix":"// before\n@AfterThrowing(value = \"...\", throwing = \"ex\")\npublic void onThrow(RuntimeException ex, Exception ctx) { ... } // compiled w/o -parameters\n// after\n@AfterThrowing(value = \"...\", throwing = \"ex\", argNames = \"ex,ctx\")\npublic void onThrow(RuntimeException ex, Exception ctx) { ... }","handlingStrategy":"validation","validationCode":"// Before wiring after-throwing, ensure at most one unbound Throwable param unless names are known.\nlong throwableParams = Arrays.stream(adviceMethod.getParameterTypes())\n    .filter(Throwable.class::isAssignableFrom).count();\nboolean namesAvailable = new DefaultParameterNameDiscoverer().getParameterNames(adviceMethod) != null;\nif (throwingName != null && throwableParams > 1 && !namesAvailable) {\n    throw new IllegalStateException(\"Ambiguous throwing binding on \" + adviceMethod\n        + \" — supply arg-names or compile with -parameters\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Compile aspects with -parameters so throwing binds by name, not by type.","Supply explicit arg-names when multiple Throwable-typed parameters exist.","Prefer a single exception-typed parameter per after-throwing advice."],"tags":["spring-aop","aspectj","after-throwing","ambiguous-binding","parameters-flag"],"analyzedSha":"e8729d043887bf0d0baf91e062e909b56eb2b708","analyzedAt":"2026-08-04T19:07:39.725Z","schemaVersion":2}