{"id":"1e929e7797f0e265","repo":"spring-projects/spring-framework","slug":"found-candidate-this-target-or-args-var","errorCode":null,"errorMessage":"Found {} candidate this(), target(), or args() variables but only one unbound argument slot","messagePattern":"Found (.+?) candidate this\\(\\), target\\(\\), or args\\(\\) variables but only one unbound argument slot","errorType":"exception","errorClass":"AmbiguousBindingException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java","lineNumber":517,"sourceCode":"\t\t\t\t}\n\t\t\t}\n\t\t\telse if (tokens[i].equals(\"args\") || tokens[i].startsWith(\"args(\")) {\n\t\t\t\tPointcutBody body = getPointcutBody(tokens, i);\n\t\t\t\ti += body.numTokensConsumed;\n\t\t\t\tList<String> candidateVarNames = new ArrayList<>();\n\t\t\t\tmaybeExtractVariableNamesFromArgs(body.text, candidateVarNames);\n\t\t\t\t// we may have found some var names that were bound in previous primitive args binding step,\n\t\t\t\t// filter them out...\n\t\t\t\tfor (String varName : candidateVarNames) {\n\t\t\t\t\tif (!alreadyBound(varName)) {\n\t\t\t\t\t\tvarNames.add(varName);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (varNames.size() > 1) {\n\t\t\tthrow new AmbiguousBindingException(\"Found \" + varNames.size() +\n\t\t\t\t\t\" candidate this(), target(), or args() variables but only one unbound argument slot\");\n\t\t}\n\t\telse if (varNames.size() == 1) {\n\t\t\tfor (int j = 0; j < this.parameterNameBindings.length; j++) {\n\t\t\t\tif (isUnbound(j)) {\n\t\t\t\t\tbindParameterName(j, varNames.get(0));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// else varNames.size must be 0 and we have nothing to bind.\n\t}\n\n\tprivate void maybeBindReferencePointcutParameter() {\n\t\tif (this.numberOfRemainingUnboundArguments > 1) {\n\t\t\tthrow new AmbiguousBindingException(\"Still \" + this.numberOfRemainingUnboundArguments +\n\t\t\t\t\t\" unbound args at reference pointcut binding stage, with no way to determine between them\");\n\t\t}","sourceCodeStart":499,"sourceCodeEnd":535,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/e8729d043887bf0d0baf91e062e909b56eb2b708/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java#L499-L535","documentation":"Thrown when the pointcut expression contains multiple candidate this/target/args binding variables but there is only one unbound argument slot. Spring cannot decide which variable name to bind. Only surfaces when raiseExceptions=true.","triggerScenarios":"A pointcut like 'target(t) && args(a, b)' yielding two candidate names while only one parameter remains unbound at this stage.","commonSituations":"Pointcuts that bind multiple variables via this/target/args but the advice method has fewer corresponding parameters; refactor mismatches.","solutions":["Make the advice method parameter count match the number of bound variables in the pointcut.","Remove extra this/target/args binding clauses from the pointcut.","Compile with -parameters and ensure each bound variable has a corresponding parameter."],"exampleFix":"// before\n@Before(\"target(t) && args(a)\")\npublic void before(Object t) { ... }\n\n// after\n@Before(\"target(t) && args(a)\")\npublic void before(Object t, Object a) { ... }","handlingStrategy":"validation","validationCode":"// Match this/target/args binding var count to unbound param count:\nint vars = extractBindingVars(this_target_args, pointcutExpression).size();\nint unbound = countUnboundParams(adviceMethod);\nassert vars <= unbound && (vars == 0 || unbound == 1);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep this()/target()/args() binding variable count equal to the number of corresponding advice parameters.","Compile with -parameters.","Avoid binding the same variable twice across clauses."],"tags":["spring-aop","aspectj","advice-binding"],"analyzedSha":"e8729d043887bf0d0baf91e062e909b56eb2b708","analyzedAt":"2026-08-04T19:07:39.725Z","schemaVersion":2}