{"record":{"id":"d3eacffee1a45620","repo":"spring-projects/spring-framework","slug":"required-to-bind-arguments-but-only-bound","errorCode":null,"errorMessage":"Required to bind {} arguments, but only bound {} (JoinPointMatch {} bound in invocation)","messagePattern":"Required to bind (.+?) arguments, but only bound (.+?) \\(JoinPointMatch (.+?) bound in invocation\\)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java","lineNumber":603,"sourceCode":"\t\t\t}\n\t\t\t// binding from returning clause\n\t\t\tif (this.returningName != null) {\n\t\t\t\tInteger index = this.argumentBindings.get(this.returningName);\n\t\t\t\tAssert.state(index != null, \"Index must not be null\");\n\t\t\t\tadviceInvocationArgs[index] = returnValue;\n\t\t\t\tnumBound++;\n\t\t\t}\n\t\t\t// binding from thrown exception\n\t\t\tif (this.throwingName != null) {\n\t\t\t\tInteger index = this.argumentBindings.get(this.throwingName);\n\t\t\t\tAssert.state(index != null, \"Index must not be null\");\n\t\t\t\tadviceInvocationArgs[index] = ex;\n\t\t\t\tnumBound++;\n\t\t\t}\n\t\t}\n\n\t\tif (numBound != this.parameterTypes.length) {\n\t\t\tthrow new IllegalStateException(\"Required to bind \" + this.parameterTypes.length +\n\t\t\t\t\t\" arguments, but only bound \" + numBound + \" (JoinPointMatch \" +\n\t\t\t\t\t(jpMatch == null ? \"was NOT\" : \"WAS\") + \" bound in invocation)\");\n\t\t}\n\n\t\treturn adviceInvocationArgs;\n\t}\n\n\n\t/**\n\t * Invoke the advice method.\n\t * @param jpMatch the JoinPointMatch that matched this execution join point\n\t * @param returnValue the return value from the method execution (may be null)\n\t * @param ex the exception thrown by the method execution (may be null)\n\t * @return the invocation result\n\t * @throws Throwable in case of invocation failure\n\t */\n\tprotected @Nullable Object invokeAdviceMethod(@Nullable JoinPointMatch jpMatch,\n\t\t\t@Nullable Object returnValue, @Nullable Throwable ex) throws Throwable {","sourceCodeStart":585,"sourceCodeEnd":621,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/69bf83ad716d0cfc4b0520a19b4d8b24c79d1538/spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java#L585-L621","documentation":"Thrown by argBinding (line 602-606) at advice invocation time when the number of bound arguments (numBound) does not equal parameterTypes.length. numBound counts the joinpoint/static-part binding plus pointcut parameter bindings plus returning/throwing bindings. A shortfall means a parameter could not be populated — usually because the JoinPointMatch was null (pointcut did not actually match at runtime, so parameterBindings was empty) or because the pointcut bound fewer variables than the method expects.","triggerScenarios":"An advice method declares more parameters than the pointcut expression binds, and the runtime JoinPointMatch is null (no bindings available). Also when a pointcut uses args(a,b) but the advice declares three parameters, or when the proxy somehow invokes advice without the matching context attached.","commonSituations":"Mismatch between pointcut binding variables and advice parameters, pointcut expression changed to bind fewer variables without updating the method, or running through a code path that does not attach the JoinPointMatch (e.g. manual invocation). The message distinguishes whether jpMatch was bound.","solutions":["Align the advice method's parameter count with the variables bound by the pointcut expression (args(), this(), target(), @annotation(), returning, throwing).","If the message says 'JoinPointMatch was NOT bound', verify the pointcut actually matches the target method and that the proxy is correctly configured.","Add explicit arg-names / use -parameters so Spring can match each parameter to a binding.","Reduce the method to only the parameters you actually bind."],"exampleFix":"// before — advice declares a param the pointcut does not bind\n@After(\"execution(* svc.*(..)) && args(payload)\")\npublic void after(JoinPoint jp, Object payload, Object extra) { ... } // extra unbound\n\n// after — drop the unbindable parameter\n@After(\"execution(* svc.*(..)) && args(payload)\")\npublic void after(JoinPoint jp, Object payload) { ... }","handlingStrategy":"validation","validationCode":"import java.lang.reflect.Method;\n\n// Sanity-check that the pointcut binds exactly as many variables as the advice needs.\n// (Heuristic: count binding forms args/this/target/@annotation occurrences vs params minus joinpoint.)\nint bindableParamCount(Method adviceMethod) {\n    int pc = adviceMethod.getParameterCount();\n    Class<?> first = pc > 0 ? adviceMethod.getParameterTypes()[0] : null;\n    boolean implicitJp = first == org.aspectj.lang.JoinPoint.class\n            || first == org.aspectj.lang.ProceedingJoinPoint.class\n            || first == org.aspectj.lang.JoinPoint.StaticPart.class;\n    return implicitJp ? pc - 1 : pc;\n}\n// Ensure your pointcut binds exactly this many variables.","typeGuard":"boolean pointcutBindsEnoughVariables(String pointcutExpr, int paramsNeedingBinding) {\n    // crude count of binding forms; refine as needed\n    int forms = 0;\n    for (String kw : new String[]{\"args(\", \"this(\", \"target(\", \"@annotation(\", \"@args(\", \"@this(\", \"@target(\"}) {\n        int idx = -1;\n        while ((idx = pointcutExpr.indexOf(kw, idx + 1)) >= 0) forms++;\n    }\n    return forms >= paramsNeedingBinding;\n}","tryCatchPattern":"// This fires at invocation time, not setup. Catch around the proxied call in integration tests:\ntry {\n    proxy.businessMethod();\n} catch (IllegalStateException ex) {\n    if (ex.getMessage().contains(\"Required to bind\") && ex.getMessage().contains(\"only bound\")) {\n        // reconcile pointcut bindings with advice parameters\n    } else { throw ex; }\n}","preventionTips":["Make pointcut binding forms (args/this/target/@annotation) equal the non-joinpoint parameter count.","Add integration tests that actually invoke the proxied method to surface this early.","Avoid declaring advice parameters the pointcut does not bind."],"tags":["spring-aop","aspectj","argument-binding","runtime","pointcut"],"backgroundTag":null,"analyzedSha":"69bf83ad716d0cfc4b0520a19b4d8b24c79d1538","analyzedAt":"2026-08-09T15:32:58.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}