{"record":{"id":"a8c750e4e22e6eac","repo":"spring-projects/spring-framework","slug":"methodinvocation-is-not-a-spring-proxymethodinvoca","errorCode":null,"errorMessage":"MethodInvocation is not a Spring ProxyMethodInvocation: {}","messagePattern":"MethodInvocation is not a Spring ProxyMethodInvocation: (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java","lineNumber":83,"sourceCode":"\n\t/**\n\t * Key used in ReflectiveMethodInvocation userAttributes map for the current joinpoint.\n\t */\n\tprotected static final String JOIN_POINT_KEY = JoinPoint.class.getName();\n\n\n\t/**\n\t * Lazily instantiate joinpoint for the current invocation.\n\t * Requires MethodInvocation to be bound with ExposeInvocationInterceptor.\n\t * <p>Do not use if access is available to the current ReflectiveMethodInvocation\n\t * (in an around advice).\n\t * @return current AspectJ joinpoint, or through an exception if we're not in a\n\t * Spring AOP invocation.\n\t */\n\tpublic static JoinPoint currentJoinPoint() {\n\t\tMethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();\n\t\tif (!(mi instanceof ProxyMethodInvocation pmi)) {\n\t\t\tthrow new IllegalStateException(\"MethodInvocation is not a Spring ProxyMethodInvocation: \" + mi);\n\t\t}\n\t\tJoinPoint jp = (JoinPoint) pmi.getUserAttribute(JOIN_POINT_KEY);\n\t\tif (jp == null) {\n\t\t\tjp = new MethodInvocationProceedingJoinPoint(pmi);\n\t\t\tpmi.setUserAttribute(JOIN_POINT_KEY, jp);\n\t\t}\n\t\treturn jp;\n\t}\n\n\n\tprivate final Class<?> declaringClass;\n\n\tprivate final String methodName;\n\n\tprivate final Class<?>[] parameterTypes;\n\n\tprotected transient Method aspectJAdviceMethod;\n","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/69bf83ad716d0cfc4b0520a19b4d8b24c79d1538/spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java#L65-L101","documentation":"Thrown by the static currentJoinPoint() helper when the AOP Alliance MethodInvocation exposed via ExposeInvocationInterceptor is not an instance of Spring's ProxyMethodInvocation. Spring's advice machinery caches the JoinPoint as a user attribute on a ProxyMethodInvocation; if some other Advice or framework drives the invocation with a plain MethodInvocation, that lookup mechanism is unavailable. The guard at line 82-84 therefore refuses to proceed rather than return a half-built join point.","triggerScenarios":"Calling AbstractAspectJAdvice.currentJoinPoint() (or any advice that delegates to it, e.g. AspectJMethodBeforeAdvice) from within a non-Spring interceptor chain — for example a custom org.aopalliance.intercept.MethodInterceptor registered outside ProxyFactory, or invoking advice directly during a unit test without a ReflectiveMethodInvocation. Also when ExposeInvocationInterceptor is absent from the advice chain yet code still calls currentJoinPoint().","commonSituations":"Manually wiring Spring AspectJ advice into a non-Spring proxy (CGLIB directly, ByteBuddy, javassist), unit-testing advice by hand-rolling a MethodInvocation, or removing ExposeInvocationInterceptor from the advisor chain while still relying on AspectJ-style thisJoinPoint binding. Occasionally seen after upgrading a custom proxy bridge between Spring AOP and another framework.","solutions":["Ensure the invocation is driven through a Spring ProxyFactory / AspectJProxyFactory so the active MethodInvocation is a ReflectiveMethodInvocation (which implements ProxyMethodInvocation).","Add ExposeInvocationInterceptor to the advice chain if it is missing — it is what publishes the current ProxyMethodInvocation via ExposeInvocationInterceptor.currentInvocation().","If calling from outside Spring AOP, wrap your target in an AspectJProxyFactory and obtain the proxy from it rather than invoking advice reflectively.","In tests, build the invocation with ReflectiveMethodInvocation.createInvocation(target, method, args, targetClass, interceptorsAndAdvice) so the instance is a ProxyMethodInvocation."],"exampleFix":"// before: invoking advice with a plain mock MethodInvocation\nadvice.invoke(new MyCustomMethodInvocation());\n\n// after: drive through a Spring proxy so currentInvocation() is a ProxyMethodInvocation\nAspectJProxyFactory factory = new AspectJProxyFactory(target);\nfactory.addAspect(myAspect);\nMyInterface proxy = factory.getProxy();\nproxy.businessMethod();","handlingStrategy":"type-guard","validationCode":"import org.springframework.aop.ProxyMethodInvocation;\nimport org.aopalliance.intercept.MethodInvocation;\nimport org.springframework.aop.interceptor.ExposeInvocationInterceptor;\n\n// Verify a Spring ProxyMethodInvocation is active before calling currentJoinPoint().\nboolean safeToCallJoinPoint() {\n    try {\n        MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();\n        return mi instanceof ProxyMethodInvocation;\n    } catch (IllegalStateException noInvocation) {\n        return false;\n    }\n}","typeGuard":"boolean isSpringProxyInvocation(org.aopalliance.intercept.MethodInvocation mi) {\n    return mi instanceof org.springframework.aop.ProxyMethodInvocation;\n}","tryCatchPattern":"try {\n    JoinPoint jp = AbstractAspectJAdvice.currentJoinPoint();\n} catch (IllegalStateException ex) {\n    if (ex.getMessage().contains(\"not a Spring ProxyMethodInvocation\")) {\n        // advice invoked outside a Spring proxy; re-route through AspectJProxyFactory\n    } else { throw ex; }\n}","preventionTips":["Always obtain advice-bearing proxies from ProxyFactory/AspectJProxyFactory, never invoke advice reflectively with a custom MethodInvocation.","Keep ExposeInvocationInterceptor in the chain when using AspectJ-style binding.","In tests, build invocations with ReflectiveMethodInvocation so they are ProxyMethodInvocations."],"tags":["spring-aop","aspectj","proxy","method-invocation","advice"],"backgroundTag":null,"analyzedSha":"69bf83ad716d0cfc4b0520a19b4d8b24c79d1538","analyzedAt":"2026-08-09T15:32:58.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}