spring-projects/spring-framework · error · IllegalStateException

No MethodInvocation found: Check that an AOP invocation is…

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

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.

Solutions

  1. 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).
  2. Do not call currentInvocation() from a different thread than the proxy invocation; capture needed data on the invoking thread and pass it along.
  3. Lower your advice precedence so it runs after ExposeInvocationInterceptor: avoid HIGHEST_PRECEDENCE for advices that need the invocation; ExposeInvocationInterceptor itself is HIGHEST_PRECEDENCE+1.
  4. Only call currentInvocation() while a proxied method is actually executing.

Example fix

// before
// manual proxy, expose interceptor omitted
ProxyFactory pf = new ProxyFactory(target);
pf.addAdvice(myAspect); // calls currentInvocation() -> null

// after
ProxyFactory pf = new ProxyFactory(target);
pf.addAdvice(ExposeInvocationInterceptor.INSTANCE); // first
pf.addAdvice(myAspect);
Defensive patterns

Strategy: validation

Validate before calling

import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
boolean exposed;
try { ExposeInvocationInterceptor.currentInvocation(); exposed = true; }
catch (IllegalStateException e) { exposed = false; }
if (!exposed) { /* add ExposeInvocationInterceptor to the chain */ }

Try / catch

try {
    MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
    // use mi
} catch (IllegalStateException e) {
    // no invocation exposed: fall back or reconfigure chain
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09). Data as JSON: /api/errors/8e7e5ea8abe651bb. Report an issue: GitHub.

Appendix: 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 69bf83ad71)