{"record":{"id":"65fbc6af771a55ce","repo":"spring-projects/spring-framework","slug":"found-unbound-primitive-arguments-with-no-way-t","errorCode":null,"errorMessage":"Found {} unbound primitive arguments with no way to distinguish between them.","messagePattern":"Found (.+?) unbound primitive arguments with no way to distinguish between them\\.","errorType":"exception","errorClass":"AmbiguousBindingException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java","lineNumber":644,"sourceCode":"\t\t\t\tsb.append(toAppend);\n\t\t\t\tsb.append(' ');\n\t\t\t\tcurrentIndex++;\n\t\t\t\tnumTokensConsumed++;\n\t\t\t}\n\n\t\t}\n\n\t\t// We looked and failed...\n\t\treturn new PointcutBody(numTokensConsumed, null);\n\t}\n\n\t/**\n\t * Match up args against unbound arguments of primitive types.\n\t */\n\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) {","sourceCodeStart":626,"sourceCodeEnd":662,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/69bf83ad716d0cfc4b0520a19b4d8b24c79d1538/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java#L626-L662","documentation":"Thrown when two or more unbound arguments of primitive types (int, long, boolean, etc.) remain at the primitive-args binding stage. Primitive arguments can only be bound via args(), and when multiple primitives share the same type (e.g., two ints), the algorithm cannot distinguish between them by type alone.","triggerScenarios":"An advice method with two same-typed primitive parameters like void before(int x, int y) where the pointcut uses args(). Both are int and thus indistinguishable by type. Only fires when setRaiseExceptions(true).","commonSituations":"Advice methods binding multiple same-typed primitive arguments, compiled without -parameters.","solutions":["Compile with -parameters so each primitive parameter name resolves directly from bytecode","Use different primitive types for each parameter if the method signature allows (int vs long vs double)","Reduce to a single primitive parameter"],"exampleFix":"// before\n@Before(\"execution(* *(int, int)) && args(x, y)\")\npublic void before(int x, int y) { ... } // 2 unbound primitives, ambiguous\n\n// after — compile with -parameters so names resolve directly\n// Or use boxable distinct types:\n@Before(\"execution(* *(int, long)) && args(x, y)\")\npublic void before(int x, long y) { ... }","handlingStrategy":"validation","validationCode":"// Count unbound primitive params; warn if >1 since they can't be distinguished by type\nlong primitiveParams = Arrays.stream(adviceMethod.getParameterTypes())\n    .filter(Class::isPrimitive).count();\nif (primitiveParams > 1 && !compiledWithParameters) {\n    throw new IllegalStateException(\n        \"Multiple primitive params (\" + primitiveParams + \") are ambiguous without -parameters\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    discoverer.getParameterNames(adviceMethod);\n} catch (AspectJAdviceParameterNameDiscoverer.AmbiguousBindingException ex) {\n    // Use -parameters, or use distinct primitive types, or reduce to one primitive param\n}","preventionTips":["Compile with — the definitive fix for primitive arg ambiguity","Use distinct primitive types (int vs long vs double) for each parameter so they are type-distinguishable","Avoid binding more than one same-typed primitive parameter in a single advice method"],"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"}