{"id":"8b86c2d5f88ea47e","repo":"spring-projects/spring-framework","slug":"expecting-to-find-arguments-to-bind-by-name-in","errorCode":null,"errorMessage":"Expecting to find {} arguments to bind by name in advice, but actually found {} arguments.","messagePattern":"Expecting to find (.+?) arguments to bind by name in advice, but actually found (.+?) arguments\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java","lineNumber":473,"sourceCode":"\t\tDefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();\n\t\tAspectJAdviceParameterNameDiscoverer adviceParameterNameDiscoverer =\n\t\t\t\tnew AspectJAdviceParameterNameDiscoverer(this.pointcut.getExpression());\n\t\tadviceParameterNameDiscoverer.setReturningName(this.returningName);\n\t\tadviceParameterNameDiscoverer.setThrowingName(this.throwingName);\n\t\t// Last in chain, so if we're called and we fail, that's bad...\n\t\tadviceParameterNameDiscoverer.setRaiseExceptions(true);\n\t\tdiscoverer.addDiscoverer(adviceParameterNameDiscoverer);\n\t\treturn discoverer;\n\t}\n\n\t@SuppressWarnings(\"NullAway\") // Dataflow analysis limitation\n\tprivate void bindExplicitArguments(int numArgumentsLeftToBind) {\n\t\tAssert.state(this.argumentNames != null, \"No argument names available\");\n\t\tthis.argumentBindings = new HashMap<>();\n\n\t\tint numExpectedArgumentNames = this.aspectJAdviceMethod.getParameterCount();\n\t\tif (this.argumentNames.length != numExpectedArgumentNames) {\n\t\t\tthrow new IllegalStateException(\"Expecting to find \" + numExpectedArgumentNames +\n\t\t\t\t\t\" arguments to bind by name in advice, but actually found \" +\n\t\t\t\t\tthis.argumentNames.length + \" arguments.\");\n\t\t}\n\n\t\t// So we match in number...\n\t\tint argumentIndexOffset = this.parameterTypes.length - numArgumentsLeftToBind;\n\t\tfor (int i = argumentIndexOffset; i < this.argumentNames.length; i++) {\n\t\t\tthis.argumentBindings.put(this.argumentNames[i], i);\n\t\t}\n\n\t\t// Check that returning and throwing were in the argument names list if\n\t\t// specified, and find the discovered argument types.\n\t\tif (this.returningName != null) {\n\t\t\tif (!this.argumentBindings.containsKey(this.returningName)) {\n\t\t\t\tthrow new IllegalStateException(\"Returning argument name '\" + this.returningName +\n\t\t\t\t\t\t\"' was not bound in advice arguments\");\n\t\t\t}\n\t\t\telse {","sourceCodeStart":455,"sourceCodeEnd":491,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/e8729d043887bf0d0baf91e062e909b56eb2b708/spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java#L455-L491","documentation":"Thrown by bindExplicitArguments (line 471-476) when the number of argumentNames does not equal the advice method's parameter count. Spring requires a 1:1 correspondence (with the implicit join-point name injected where applicable) before it can build the argumentBindings map.","triggerScenarios":"Providing arg-names with the wrong count: fewer or more names than the advice method declares parameters; forgetting to account for a JoinPoint/ProceedingJoinPoint/StaticPart parameter; supplying names for returning/throwing parameters inconsistently.","commonSituations":"Editing an advice method signature (adding/removing a param) without updating arg-names; miscounting because of an implicit join-point parameter; copy-paste between advice methods with different arities.","solutions":["Make arg-names list exactly one name per advice method parameter (including any join-point/returning/throwing params).","If a JoinPoint/ProceedingJoinPoint/StaticPart param is present, note Spring may inject 'THIS_JOIN_POINT' automatically only when the count is off by exactly one (see line 273); otherwise align counts manually.","Remove arg-names and let discovery work (compile with -parameters) when unsure.","Recount parameters after any signature change and update arg-names in lockstep."],"exampleFix":"// before: method has 2 params, only 1 name given\n@AfterReturning(value = \"args(req)\", returning = \"ret\", argNames = \"req\")\npublic void log(Object req, Object ret) { ... }\n// after\n@AfterReturning(value = \"args(req)\", returning = \"ret\", argNames = \"req,ret\")\npublic void log(Object req, Object ret) { ... }","handlingStrategy":"validation","validationCode":"// Verify arg-names count equals parameter count before passing it in.\nString[] tokens = argNames.split(\",\");\nif (tokens.length != adviceMethod.getParameterCount()) {\n    throw new IllegalStateException(\"arg-names has \" + tokens.length\n        + \" tokens but the advice method declares \" + adviceMethod.getParameterCount());\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Maintain a 1:1 mapping between arg-names tokens and advice parameters.","Recount arg-names whenever the advice method signature changes.","Prefer -parameters discovery over hand-maintained arg-names to avoid drift."],"tags":["spring-aop","aspectj","argument-binding","arity-mismatch","configuration"],"analyzedSha":"e8729d043887bf0d0baf91e062e909b56eb2b708","analyzedAt":"2026-08-04T19:07:39.725Z","schemaVersion":2}