spring-projects/spring-framework · error · IllegalStateException
No MethodInvocation found: Check that an AOP invocation is i
Error message
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.
What it means
ExposeInvocationInterceptor.currentInvocation() throws IllegalStateException when the thread-local holding the current MethodInvocation is null. ExposeInvocationInterceptor (order HIGHEST_PRECEDENCE+1) sets the thread-local as it enters the chain; this error means either there is no AOP invocation in progress, the interceptor is not in the chain, the call happened on a different thread, or an advice with PriorityOrdered.HIGHEST_PRECEDENCE ran before it and tried to read the invocation.
Source
Thrown at spring-aop/src/main/java/org/springframework/aop/interceptor/ExposeInvocationInterceptor.java:74
public String toString() {
return ExposeInvocationInterceptor.class.getName() +".ADVISOR";
}
};
private static final ThreadLocal<MethodInvocation> invocation =
new NamedThreadLocal<>("Current AOP method invocation");
/**
* Return the AOP Alliance MethodInvocation object associated with the current invocation.
* @return the invocation object associated with the current invocation
* @throws IllegalStateException if there is no AOP invocation in progress,
* or if the ExposeInvocationInterceptor was not added to this interceptor chain
*/
public static MethodInvocation currentInvocation() throws IllegalStateException {
MethodInvocation mi = invocation.get();
if (mi == null) {
throw new IllegalStateException(
"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.");
}
return mi;
}
/**
* Ensures that only the canonical instance can be created.
*/
private ExposeInvocationInterceptor() {
}
@Override
public @Nullable Object invoke(MethodInvocation mi) throws Throwable {View on GitHub (pinned to e8729d0438)
Solutions
- Keep ExposeInvocationInterceptor.ADVISOR in the chain (Spring registers it by default) and read currentInvocation() only on the invoking thread.
- Order custom advice strictly after HIGHEST_PRECEDENCE+1 so ExposeInvocationInterceptor has already populated the thread-local.
- Capture any needed invocation data on the calling thread before dispatching to another thread.
Example fix
// before
@Order(Ordered.HIGHEST_PRECEDENCE)
public class MyAdvice implements MethodInterceptor {
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation cur = ExposeInvocationInterceptor.currentInvocation(); // null -> error 108
return mi.proceed();
}
}
// after
@Order(Ordered.HIGHEST_PRECEDENCE + 10) // after ExposeInvocationInterceptor
public class MyAdvice implements MethodInterceptor {
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation cur = ExposeInvocationInterceptor.currentInvocation();
return mi.proceed();
}
} Defensive patterns
Strategy: try-catch
Validate before calling
boolean invocationAvailable() {
try {
ExposeInvocationInterceptor.currentInvocation();
return true;
} catch (IllegalStateException ex) {
return false;
}
} Try / catch
try {
MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
} catch (IllegalStateException ex) {
// not in an AOP joinpoint or wrong thread; handle absence
} Prevention
- Keep ExposeInvocationInterceptor.ADVISOR in every Spring proxy chain (default behaviour).
- Order custom advice after HIGHEST_PRECEDENCE+1.
- Never read currentInvocation() from a different thread than the invocation.
When it happens
Trigger: Calling ExposeInvocationInterceptor.currentInvocation() from a non-proxied call, from a worker/CompletableFuture thread, or from an advice ordered HIGHEST_PRECEDENCE that executes ahead of ExposeInvocationInterceptor.
Common situations: Accessing the invocation inside @Async/@Scheduled tasks that hop threads; custom PriorityOrdered advice that needs the joinpoint; AspectJ pointcuts used outside a proxied bean; serialisation/deserialisation losing the thread context.
Related errors
- DeclarePrecedence not presently supported in Spring AOP
- Cannot find current proxy: Set 'exposeProxy' property on Adv
- AOP configuration seems to be invalid: tried calling method
- MethodInvocation is not a Spring ProxyMethodInvocation: {}
- 'argumentNames' property of AbstractAspectJAdvice contains a
AI-assisted analysis of spring-projects/spring-framework@e8729d0438 (2026-08-04).
Data as JSON: /data/errors/8e7e5ea8abe651bb.json.
Report an issue: GitHub.