{"record":{"id":"8e7e5ea8abe651bb","repo":"spring-projects/spring-framework","slug":"no-methodinvocation-found-check-that-an-aop-invoc","errorCode":null,"errorMessage":"No MethodInvocation found: Check that an AOP invocation is in progress and that the ExposeInvocationInterceptor is upfront in the interceptor chain. Specifically, note that advices with order HIGHEST_PRECEDENCE will execute before ExposeInvocationInterceptor! In addition, ExposeInvocationInterceptor and ExposeInvocationInterceptor.currentInvocation() must be invoked from the same thread.","messagePattern":"No MethodInvocation found: Check that an AOP invocation is in progress and that the ExposeInvocationInterceptor is upfront in the interceptor chain\\. Specifically, note that advices with order HIGHEST_PRECEDENCE will execute before ExposeInvocationInterceptor! In addition, ExposeInvocationInterceptor and ExposeInvocationInterceptor\\.currentInvocation\\(\\) must be invoked from the same thread\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/interceptor/ExposeInvocationInterceptor.java","lineNumber":74,"sourceCode":"\t\tpublic String toString() {\n\t\t\treturn ExposeInvocationInterceptor.class.getName() +\".ADVISOR\";\n\t\t}\n\t};\n\n\tprivate static final ThreadLocal<MethodInvocation> invocation =\n\t\t\tnew NamedThreadLocal<>(\"Current AOP method invocation\");\n\n\n\t/**\n\t * Return the AOP Alliance MethodInvocation object associated with the current invocation.\n\t * @return the invocation object associated with the current invocation\n\t * @throws IllegalStateException if there is no AOP invocation in progress,\n\t * or if the ExposeInvocationInterceptor was not added to this interceptor chain\n\t */\n\tpublic static MethodInvocation currentInvocation() throws IllegalStateException {\n\t\tMethodInvocation mi = invocation.get();\n\t\tif (mi == null) {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"No MethodInvocation found: Check that an AOP invocation is in progress and that the \" +\n\t\t\t\t\t\"ExposeInvocationInterceptor is upfront in the interceptor chain. Specifically, note that \" +\n\t\t\t\t\t\"advices with order HIGHEST_PRECEDENCE will execute before ExposeInvocationInterceptor! \" +\n\t\t\t\t\t\"In addition, ExposeInvocationInterceptor and ExposeInvocationInterceptor.currentInvocation() \" +\n\t\t\t\t\t\"must be invoked from the same thread.\");\n\t\t}\n\t\treturn mi;\n\t}\n\n\n\t/**\n\t * Ensures that only the canonical instance can be created.\n\t */\n\tprivate ExposeInvocationInterceptor() {\n\t}\n\n\t@Override\n\tpublic @Nullable Object invoke(MethodInvocation mi) throws Throwable {","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/69bf83ad716d0cfc4b0520a19b4d8b24c79d1538/spring-aop/src/main/java/org/springframework/aop/interceptor/ExposeInvocationInterceptor.java#L56-L92","documentation":"Thrown by ExposeInvocationInterceptor.currentInvocation() (line 72-79) when the thread-local holding the current MethodInvocation is empty. The invocation is exposed only while ExposeInvocationInterceptor is on the chain and actively proceeding; if no AOP invocation is in progress, the interceptor was not added (or was ordered after the caller), or currentInvocation() is called from a different thread than the proxy invocation, the thread-local is null and an IllegalStateException is raised.","triggerScenarios":"Calling ExposeInvocationInterceptor.currentInvocation() outside any proxied method call, from a background thread that was not the invoking thread, or from an advice whose order is HIGHEST_PRECEDENCE (which runs before ExposeInvocationInterceptor, whose order is HIGHEST_PRECEDENCE+1). Also when the pointcut/aspect tries to read the invocation but the expose interceptor was never added to the chain.","commonSituations":"Using AspectJ 'bean()' pointcut or code that reads MethodInvocation.currentInvocation() while ExposeInvocationInterceptor is missing. An advice annotated @Order(HIGHEST_PRECEDENCE) running before the expose interceptor. Spawning work onto another thread inside an advised method and calling currentInvocation() there.","solutions":["Ensure ExposeInvocationInterceptor (or its ADVISOR singleton) is in the interceptor chain - Spring adds it automatically for most proxies; for manual ProxyFactory, add pf.addAdvice(0, ExposeInvocationInterceptor.INSTANCE).","Do not call currentInvocation() from a different thread than the proxy invocation; capture needed data on the invoking thread and pass it along.","Lower your advice precedence so it runs after ExposeInvocationInterceptor: avoid HIGHEST_PRECEDENCE for advices that need the invocation; ExposeInvocationInterceptor itself is HIGHEST_PRECEDENCE+1.","Only call currentInvocation() while a proxied method is actually executing."],"exampleFix":"// before\n// manual proxy, expose interceptor omitted\nProxyFactory pf = new ProxyFactory(target);\npf.addAdvice(myAspect); // calls currentInvocation() -> null\n\n// after\nProxyFactory pf = new ProxyFactory(target);\npf.addAdvice(ExposeInvocationInterceptor.INSTANCE); // first\npf.addAdvice(myAspect);","handlingStrategy":"validation","validationCode":"import org.springframework.aop.interceptor.ExposeInvocationInterceptor;\nboolean exposed;\ntry { ExposeInvocationInterceptor.currentInvocation(); exposed = true; }\ncatch (IllegalStateException e) { exposed = false; }\nif (!exposed) { /* add ExposeInvocationInterceptor to the chain */ }","typeGuard":null,"tryCatchPattern":"try {\n    MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();\n    // use mi\n} catch (IllegalStateException e) {\n    // no invocation exposed: fall back or reconfigure chain\n}","preventionTips":["Keep ExposeInvocationInterceptor near the front of the chain (it is HIGHEST_PRECEDENCE+1).","Do not call currentInvocation() from a different thread than the proxy call.","Avoid HIGHEST_PRECEDENCE on advices that need the exposed invocation."],"tags":["spring-aop","invocation","thread-local","ordering"],"backgroundTag":null,"analyzedSha":"69bf83ad716d0cfc4b0520a19b4d8b24c79d1538","analyzedAt":"2026-08-09T15:32:58.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}