{"record":{"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/69bf83ad716d0cfc4b0520a19b4d8b24c79d1538/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java#L641-L677","documentation":"Thrown when exactly one primitive argument slot remains but the args() expression in the pointcut yields multiple candidate variable names. Spring cannot determine which candidate binds to the single primitive slot.","triggerScenarios":"A pointcut like args(a, b) with an advice method that has exactly one primitive parameter — e.g. void before(int a). The algorithm finds two candidate variable names but only one primitive slot. Only fires when setRaiseExceptions(true).","commonSituations":"Over-specified args() binding with fewer advice parameters than bindings, compiled without -parameters.","solutions":["Compile with -parameters to resolve names directly","Reduce args() in the pointcut to a single binding variable","Add the matching number of parameters to the advice method"],"exampleFix":"// before\n@Before(\"args(a, b)\")\npublic void before(int a) { ... } // 2 candidates, 1 primitive slot\n\n// after\n@Before(\"args(a)\")\npublic void before(int a) { ... }","handlingStrategy":"validation","validationCode":"// If the advice has exactly one primitive param, ensure args() in the pointcut has at most one binding variable\nint primitiveSlots = (int) Arrays.stream(adviceMethod.getParameterTypes())\n    .filter(Class::isPrimitive).count();\nif (primitiveSlots == 1 && pointcutExpr.contains(\"args(\")) {\n    // Count binding variables in args(...) — if >1, this will throw\n    logger.warn(\"Multiple args() binding variables with one primitive slot may be ambiguous\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    discoverer.getParameterNames(adviceMethod);\n} catch (AspectJAdviceParameterNameDiscoverer.AmbiguousBindingException ex) {\n    // Reduce args() to a single binding variable, or add params\n}","preventionTips":["Compile with -parameters","Match args() binding variable count to the number of primitive advice parameters"],"tags":["spring-aop","aspectj","primitive-args","parameter-binding"],"backgroundTag":null,"analyzedSha":"69bf83ad716d0cfc4b0520a19b4d8b24c79d1538","analyzedAt":"2026-08-09T15:32:58.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}