{"id":"eb95bfafd84b5086","repo":"spring-projects/spring-framework","slug":"binding-of-returning-parameter-is-ambiguous","errorCode":null,"errorMessage":"Binding of returning parameter '{}' is ambiguous: there are {} candidates. Consider compiling with -parameters in order to make declared parameter names available.","messagePattern":"Binding of returning parameter '(.+?)' is ambiguous: there are (.+?) candidates\\. Consider compiling with -parameters in order to make declared parameter names available\\.","errorType":"exception","errorClass":"AmbiguousBindingException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java","lineNumber":370,"sourceCode":"\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 */\n\tprivate void maybeBindReturningVariable() {\n\t\tif (this.numberOfRemainingUnboundArguments == 0) {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"Algorithm assumes that there must be at least one unbound parameter on entry to this method\");\n\t\t}\n\n\t\tif (this.returningName != null) {\n\t\t\tif (this.numberOfRemainingUnboundArguments > 1) {\n\t\t\t\tthrow new AmbiguousBindingException(\"Binding of returning parameter '\" + this.returningName +\n\t\t\t\t\t\t\"' is ambiguous: there are \" + this.numberOfRemainingUnboundArguments + \" candidates. \" +\n\t\t\t\t\t\t\"Consider compiling with -parameters in order to make declared parameter names available.\");\n\t\t\t}\n\n\t\t\t// We're all set... find the unbound parameter, and bind it.\n\t\t\tfor (int i = 0; i < this.parameterNameBindings.length; i++) {\n\t\t\t\tif (this.parameterNameBindings[i] == null) {\n\t\t\t\t\tbindParameterName(i, this.returningName);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Parse the string pointcut expression looking for:\n\t * &#64;this, &#64;target, &#64;args, &#64;within, &#64;withincode, &#64;annotation.\n\t * If we find one of these pointcut expressions, try and extract a candidate variable","sourceCodeStart":352,"sourceCodeEnd":388,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/e8729d043887bf0d0baf91e062e909b56eb2b708/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java#L352-L388","documentation":"Thrown by AspectJAdviceParameterNameDiscoverer when a 'returning' name was specified on an @AfterReturning advice but more than one advice-method parameter remains unbound at the returning-binding stage. Spring cannot decide which of the multiple candidate parameters the return value should bind to, because parameter names were not compiled in (-parameters flag absent). Only surfaces when raiseExceptions=true; otherwise the discoverer returns null and the failure is logged.","triggerScenarios":"An @AfterReturning advice method with multiple untyped/unbound parameters (e.g. two Objects) combined with returning=\"someName\", where the pointcut expression and prior binding stages (JoinPoint, throwing, annotation) did not resolve enough parameters to leave exactly one unbound slot.","commonSituations":"Advice methods written with several parameters that are not named in bytecode; migrating from ajc-compiled aspects (which embed parameter names) to javac-compiled ones; upgrading Spring versions where stricter binding checks were added.","solutions":["Compile with javac -parameters (or <parameters>true</parameters> in maven-compiler-plugin / compilerArgs in Gradle) so real parameter names are available.","Reduce the advice method to exactly one unbound parameter at the returning stage by adding explicit pointcut binding (this/target/args/annotation) for the other parameters.","Remove the extra parameters from the advice signature that are not actually needed.","If using @AfterReturning, ensure the returning attribute type matches exactly one parameter."],"exampleFix":"// before\n@AfterReturning(pointcut=\"execution(* com.acme.*.*(..))\", returning=\"ret\")\npublic void after(Object ret, Object extra) { ... }\n\n// after\n@AfterReturning(pointcut=\"execution(* com.acme.*.*(..))\", returning=\"ret\")\npublic void after(Object ret) { ... }","handlingStrategy":"validation","validationCode":"// Compile with -parameters; verify before deploying:\n// javac -parameters ...\n// or in advice, keep exactly one unbound param at the returning stage.","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always compile with -parameters in any project using Spring AOP advice binding.","Keep @AfterReturning advice methods to the minimum parameters needed.","Enable raiseExceptions=true only in tests to surface binding ambiguity early."],"tags":["spring-aop","aspectj","advice-binding","configuration"],"analyzedSha":"e8729d043887bf0d0baf91e062e909b56eb2b708","analyzedAt":"2026-08-04T19:07:39.725Z","schemaVersion":2}