{"record":{"id":"3d08ce60bf228d77","repo":"spring-projects/spring-framework","slug":"still-unbound-args-at-reference-pointcut-bindin","errorCode":null,"errorMessage":"Still {} unbound args at reference pointcut binding stage, with no way to determine between them","messagePattern":"Still (.+?) unbound args at reference pointcut binding stage, with no way to determine between them","errorType":"exception","errorClass":"AmbiguousBindingException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java","lineNumber":533,"sourceCode":"\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}\n\n\t\tList<String> varNames = new ArrayList<>();\n\t\tString[] tokens = StringUtils.tokenizeToStringArray(this.pointcutExpression, \" \");\n\t\tfor (int i = 0; i < tokens.length; i++) {\n\t\t\tString toMatch = tokens[i];\n\t\t\tif (toMatch.startsWith(\"!\")) {\n\t\t\t\ttoMatch = toMatch.substring(1);\n\t\t\t}\n\t\t\tint firstParenIndex = toMatch.indexOf('(');\n\t\t\tif (firstParenIndex != -1) {\n\t\t\t\ttoMatch = toMatch.substring(0, firstParenIndex);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (tokens.length < i + 2) {\n\t\t\t\t\t// no \"(\" and nothing following\n\t\t\t\t\tcontinue;","sourceCodeStart":515,"sourceCodeEnd":551,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/69bf83ad716d0cfc4b0520a19b4d8b24c79d1538/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java#L515-L551","documentation":"Thrown by AspectJAdviceParameterNameDiscoverer at the reference pointcut binding stage (the final deduction stage) when more than one argument remains unbound. A reference pointcut is a named pointcut referenced in the expression (e.g. com.xyz.MyPointcuts.myPc()); the algorithm can only bind one slot from it.","triggerScenarios":"An advice method with two or more remaining unbound parameters whose pointcut references a named pointcut exposing a binding variable — e.g. @Before(\"com.x.MyAspect.myPc(p)\") void before(Object p, Object other). Only fires when setRaiseExceptions(true).","commonSituations":"Complex composed pointcuts referencing shared pointcut definitions, with advice methods that have extra unmatched parameters, compiled without -parameters.","solutions":["Compile with -parameters so real parameter names resolve without deduction","Add bindings for remaining parameters via other designators (args, this, target, annotation) earlier in the algorithm","Reduce the advice method parameters so at most one is unbound by this stage"],"exampleFix":"// before — 2 unbound params at reference pointcut stage\n@Before(\"com.example.CommonPointcuts.businessOp(p)\")\npublic void before(Object p, Object extra) { ... }\n\n// after\n@Before(\"com.example.CommonPointcuts.businessOp(p) && args(extra)\")\npublic void before(Object p, Object extra) { ... }","handlingStrategy":"validation","validationCode":"// This is the last deduction stage; if >1 param is still unbound, deduction cannot succeed.\n// Best prevention: compile with -parameters so the discoverer is never consulted.\nif (!compiledWithParameters) {\n    int unbound = adviceMethod.getParameterCount();\n    // subtract JoinPoint, returning, throwing, all bindings you know about\n    if (unbound > 1) {\n        logger.warn(\"Advice may fail parameter deduction at reference pointcut stage; compile with -parameters\");\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    discoverer.getParameterNames(adviceMethod);\n} catch (AspectJAdviceParameterNameDiscoverer.AmbiguousBindingException ex) {\n    // Add more bindings or compile with -parameters\n}","preventionTips":["Compile with -parameters — this is the definitive fix for all deduction-stage ambiguities","Add explicit bindings (args/this/target/annotation) for every advice parameter before the reference pointcut stage"],"tags":["spring-aop","aspectj","reference-pointcut","parameter-binding"],"backgroundTag":null,"analyzedSha":"69bf83ad716d0cfc4b0520a19b4d8b24c79d1538","analyzedAt":"2026-08-09T15:32:58.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}