spring-projects/spring-framework · error · IllegalStateException

MethodInvocation is not a Spring ProxyMethodInvocation

Error message

MethodInvocation is not a Spring ProxyMethodInvocation: {}

What it means

Thrown in AspectJExpressionPointcut.matches(method, targetClass, args) when the current thread-bound MethodInvocation (from ExposeInvocationInterceptor.currentInvocation()) is not a Spring ProxyMethodInvocation. This runtime-args matching path needs the proxy to correctly resolve this() bindings.

Solutions

  1. Ensure the interceptor chain uses Spring's ReflectiveMethodInvocation / CglibMethodInvocation
  2. Avoid mixing non-Spring MethodInvocation implementations in Spring-advised proxies
  3. Register ExposeInvocationInterceptor only within Spring's own proxy infrastructure

Example fix

// before — custom MethodInvocation pushed into ExposeInvocationInterceptor
ExposeInvocationInterceptor.currentInvocation() returns non-Spring MI

// after — use Spring ProxyMethodInvocation in the chain
ReflectiveMethodInvocation springMi = ...;
// springMi implements ProxyMethodInvocation
Defensive patterns

Strategy: type-guard

Type guard

// Type guard: check the current invocation is a ProxyMethodInvocation before relying on proxy state
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.ProxyMethodInvocation;
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;

MethodInvocation curr = ExposeInvocationInterceptor.currentInvocation();
if (curr instanceof ProxyMethodInvocation pmi) {
    Object proxy = pmi.getProxy(); // safe
} else {
    // Cannot resolve this() binding — skip or handle gracefully
}

Prevention

When it happens

Trigger: An interceptor chain that uses ExposeInvocationInterceptor but pushes a non-Spring MethodInvocation into the thread local, or a non-Spring AOP Alliance interceptor running in the same thread as Spring advice matching.

Common situations: Mixing Spring AOP with other AOP Alliance frameworks, or custom MethodInvocation implementations that participate in Spring's ExposeInvocationInterceptor mechanism.

Related errors


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

Appendix: source

Thrown at spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJExpressionPointcut.java:359

	public boolean isRuntime() {
		return obtainPointcutExpression().mayNeedDynamicTest();
	}

	@Override
	public boolean matches(Method method, Class<?> targetClass, @Nullable Object... args) {
		ShadowMatch shadowMatch = getTargetShadowMatch(method, targetClass);

		// Bind Spring AOP proxy to AspectJ "this" and Spring AOP target to AspectJ target,
		// consistent with return of MethodInvocationProceedingJoinPoint
		ProxyMethodInvocation pmi = null;
		Object targetObject = null;
		Object thisObject = null;
		try {
			MethodInvocation curr = ExposeInvocationInterceptor.currentInvocation();
			if (curr.getMethod() == method) {
				targetObject = curr.getThis();
				if (!(curr instanceof ProxyMethodInvocation currPmi)) {
					throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + curr);
				}
				pmi = currPmi;
				thisObject = pmi.getProxy();
			}
		}
		catch (IllegalStateException ex) {
			// No current invocation...
			if (logger.isDebugEnabled()) {
				logger.debug("Could not access current invocation - matching with limited context: " + ex);
			}
		}

		try {
			JoinPointMatch joinPointMatch = shadowMatch.matchesJoinPoint(thisObject, targetObject, args);

			/*
			 * Do a final check to see if any this(TYPE) kind of residue match. For
			 * this purpose, we use the original method's (proxy method's) shadow to

View on GitHub (pinned to 69bf83ad71)