{"id":"b2332982c70f003d","repo":"spring-projects/spring-framework","slug":"still-unbound-args-at-this-target-args-bi","errorCode":null,"errorMessage":"Still {} unbound args at this()/target()/args() binding stage, with no way to determine between them","messagePattern":"Still (.+?) unbound args at this\\(\\)/target\\(\\)/args\\(\\) 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":483,"sourceCode":"\t\t\treturn;\n\t\t}\n\t\tString[] tokens = StringUtils.tokenizeToStringArray(argsSpec, \",\");\n\t\tfor (int i = 0; i < tokens.length; i++) {\n\t\t\ttokens[i] = tokens[i].strip();\n\t\t\tString varName = maybeExtractVariableName(tokens[i]);\n\t\t\tif (varName != null) {\n\t\t\t\tvarNames.add(varName);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Parse the string pointcut expression looking for this(), target() and args() expressions.\n\t * If we find one, try and extract a candidate variable name and bind it.\n\t */\n\tprivate void maybeBindThisOrTargetOrArgsFromPointcutExpression() {\n\t\tif (this.numberOfRemainingUnboundArguments > 1) {\n\t\t\tthrow new AmbiguousBindingException(\"Still \" + this.numberOfRemainingUnboundArguments +\n\t\t\t\t\t\" unbound args at this()/target()/args() 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\tif (tokens[i].equals(\"this\") ||\n\t\t\t\t\ttokens[i].startsWith(\"this(\") ||\n\t\t\t\t\ttokens[i].equals(\"target\") ||\n\t\t\t\t\ttokens[i].startsWith(\"target(\")) {\n\t\t\t\tPointcutBody body = getPointcutBody(tokens, i);\n\t\t\t\ti += body.numTokensConsumed;\n\t\t\t\tString varName = maybeExtractVariableName(body.text);\n\t\t\t\tif (varName != null) {\n\t\t\t\t\tvarNames.add(varName);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (tokens[i].equals(\"args\") || tokens[i].startsWith(\"args(\")) {","sourceCodeStart":465,"sourceCodeEnd":501,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/e8729d043887bf0d0baf91e062e909b56eb2b708/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java#L465-L501","documentation":"Thrown at the this()/target()/args() binding stage when more than one parameter remains unbound. With multiple unbound slots and no compiled parameter names, Spring has no way to assign the single candidate variable extracted from this/target/args to the right slot. Only surfaces when raiseExceptions=true.","triggerScenarios":"An advice method with two or more unbound non-primitive parameters reached the this/target/args stage without prior stages (JoinPoint, throwing, annotation, returning) reducing the unbound count to one.","commonSituations":"Advice methods with several parameters where only some are bound via the pointcut and the rest are ambiguous; missing -parameters compiler flag.","solutions":["Compile with -parameters so all parameter names are available and ambiguity disappears.","Bind the extra parameters explicitly via returning, throwing, or annotation bindings so exactly one remains at this stage.","Remove unnecessary parameters from the advice method."],"exampleFix":"// before\n@Before(\"execution(* com.acme.*.*(..)) && target(t)\")\npublic void before(Object t, Object ctx) { ... }\n\n// after\n@Before(\"execution(* com.acme.*.*(..)) && target(t)\")\npublic void before(Object t) { ... }\n// or compile with -parameters","handlingStrategy":"validation","validationCode":"// Ensure at most one unbound param remains before this/target/args stage; simplest: compile -parameters.\n// Equivalent manual check: reduce advice param count so only one is left unbound after JoinPoint/throwing/annotation/returning stages.","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Compile with -parameters.","Bind every advice parameter via returning/throwing/annotation/args/this/target explicitly.","Keep advice signatures minimal."],"tags":["spring-aop","aspectj","advice-binding","configuration"],"analyzedSha":"e8729d043887bf0d0baf91e062e909b56eb2b708","analyzedAt":"2026-08-04T19:07:39.725Z","schemaVersion":2}