{"id":"f88a1e975067818e","repo":"spring-projects/spring-framework","slug":"found-candidate-variable-names-but-only-one-can","errorCode":null,"errorMessage":"Found {} candidate variable names but only one candidate binding slot when matching primitive args","messagePattern":"Found (.+?) candidate variable names but only one candidate binding slot when matching primitive args","errorType":"exception","errorClass":"AmbiguousBindingException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java","lineNumber":659,"sourceCode":"\tprivate void maybeBindPrimitiveArgsFromPointcutExpression() {\n\t\tint numUnboundPrimitives = countNumberOfUnboundPrimitiveArguments();\n\t\tif (numUnboundPrimitives > 1) {\n\t\t\tthrow new AmbiguousBindingException(\"Found \" + numUnboundPrimitives +\n\t\t\t\t\t\" unbound primitive arguments with no way to distinguish between them.\");\n\t\t}\n\t\tif (numUnboundPrimitives == 1) {\n\t\t\t// Look for arg variable and bind it if we find exactly one...\n\t\t\tList<String> varNames = new ArrayList<>();\n\t\t\tString[] tokens = StringUtils.tokenizeToStringArray(this.pointcutExpression, \" \");\n\t\t\tfor (int i = 0; i < tokens.length; i++) {\n\t\t\t\tif (tokens[i].equals(\"args\") || tokens[i].startsWith(\"args(\")) {\n\t\t\t\t\tPointcutBody body = getPointcutBody(tokens, i);\n\t\t\t\t\ti += body.numTokensConsumed;\n\t\t\t\t\tmaybeExtractVariableNamesFromArgs(body.text, varNames);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (varNames.size() > 1) {\n\t\t\t\tthrow new AmbiguousBindingException(\"Found \" + varNames.size() +\n\t\t\t\t\t\t\" candidate variable names but only one candidate binding slot when matching primitive args\");\n\t\t\t}\n\t\t\telse if (varNames.size() == 1) {\n\t\t\t\t// 1 primitive arg, and one candidate...\n\t\t\t\tfor (int i = 0; i < this.argumentTypes.length; i++) {\n\t\t\t\t\tif (isUnbound(i) && this.argumentTypes[i].isPrimitive()) {\n\t\t\t\t\t\tbindParameterName(i, varNames.get(0));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/*\n\t * Return true if the parameter name binding for the given parameter\n\t * index has not yet been assigned.\n\t */","sourceCodeStart":641,"sourceCodeEnd":677,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/e8729d043887bf0d0baf91e062e909b56eb2b708/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java#L641-L677","documentation":"Thrown when the args() clause of the pointcut yields multiple candidate variable names for primitive binding but only one unbound primitive slot exists. Spring cannot decide which name maps to the single primitive parameter. Only surfaces when raiseExceptions=true.","triggerScenarios":"A pointcut with args(a, b) where both a and b are candidate names but only one primitive parameter is unbound.","commonSituations":"Pointcut args() lists more variables than the advice method has primitive parameters; mismatched refactor.","solutions":["Match the number of args() binding variables to the number of primitive parameters in the advice.","Use wildcards (*) in args() for parameters you do not want to bind.","Compile with -parameters for full disambiguation."],"exampleFix":"// before\n@Before(\"execution(* com.acme.*.*(int,int)) && args(a, b)\")\npublic void before(int a) { ... }\n\n// after\n@Before(\"execution(* com.acme.*.*(int,int)) && args(a, *)\")\npublic void before(int a) { ... }","handlingStrategy":"validation","validationCode":"// Match args() primitive var count to unbound primitive param count:\nint argsVars = countArgsBindingVars(pointcutExpression);\nint unboundPrimitives = countUnboundPrimitiveParams(adviceMethod);\nassert argsVars == unboundPrimitives;","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use wildcards (*) in args() for primitives you do not bind.","Compile with -parameters.","Keep args() variable list and advice primitive params in sync."],"tags":["spring-aop","aspectj","advice-binding","primitive"],"analyzedSha":"e8729d043887bf0d0baf91e062e909b56eb2b708","analyzedAt":"2026-08-04T19:07:39.725Z","schemaVersion":2}