spring-projects/spring-framework · error · IllegalStateException

MethodInvocation is not a Spring ProxyMethodInvocation

Error message

MethodInvocation is not a Spring ProxyMethodInvocation: {}

What it means

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.

Solutions

  1. Ensure the invocation is driven through a Spring ProxyFactory / AspectJProxyFactory so the active MethodInvocation is a ReflectiveMethodInvocation (which implements ProxyMethodInvocation).
  2. Add ExposeInvocationInterceptor to the advice chain if it is missing — it is what publishes the current ProxyMethodInvocation via ExposeInvocationInterceptor.currentInvocation().
  3. If calling from outside Spring AOP, wrap your target in an AspectJProxyFactory and obtain the proxy from it rather than invoking advice reflectively.
  4. In tests, build the invocation with ReflectiveMethodInvocation.createInvocation(target, method, args, targetClass, interceptorsAndAdvice) so the instance is a ProxyMethodInvocation.

Example fix

// before: invoking advice with a plain mock MethodInvocation
advice.invoke(new MyCustomMethodInvocation());

// after: drive through a Spring proxy so currentInvocation() is a ProxyMethodInvocation
AspectJProxyFactory factory = new AspectJProxyFactory(target);
factory.addAspect(myAspect);
MyInterface proxy = factory.getProxy();
proxy.businessMethod();
Defensive patterns

Strategy: type-guard

Validate before calling

import org.springframework.aop.ProxyMethodInvocation;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;

// Verify a Spring ProxyMethodInvocation is active before calling currentJoinPoint().
boolean safeToCallJoinPoint() {
    try {
        MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
        return mi instanceof ProxyMethodInvocation;
    } catch (IllegalStateException noInvocation) {
        return false;
    }
}

Type guard

boolean isSpringProxyInvocation(org.aopalliance.intercept.MethodInvocation mi) {
    return mi instanceof org.springframework.aop.ProxyMethodInvocation;
}

Try / catch

try {
    JoinPoint jp = AbstractAspectJAdvice.currentJoinPoint();
} catch (IllegalStateException ex) {
    if (ex.getMessage().contains("not a Spring ProxyMethodInvocation")) {
        // advice invoked outside a Spring proxy; re-route through AspectJProxyFactory
    } else { throw ex; }
}

Prevention

When it happens

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

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

Related errors


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

Appendix: source

Thrown at spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java:83

	/**
	 * Key used in ReflectiveMethodInvocation userAttributes map for the current joinpoint.
	 */
	protected static final String JOIN_POINT_KEY = JoinPoint.class.getName();


	/**
	 * Lazily instantiate joinpoint for the current invocation.
	 * Requires MethodInvocation to be bound with ExposeInvocationInterceptor.
	 * <p>Do not use if access is available to the current ReflectiveMethodInvocation
	 * (in an around advice).
	 * @return current AspectJ joinpoint, or through an exception if we're not in a
	 * Spring AOP invocation.
	 */
	public static JoinPoint currentJoinPoint() {
		MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
		if (!(mi instanceof ProxyMethodInvocation pmi)) {
			throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
		}
		JoinPoint jp = (JoinPoint) pmi.getUserAttribute(JOIN_POINT_KEY);
		if (jp == null) {
			jp = new MethodInvocationProceedingJoinPoint(pmi);
			pmi.setUserAttribute(JOIN_POINT_KEY, jp);
		}
		return jp;
	}


	private final Class<?> declaringClass;

	private final String methodName;

	private final Class<?>[] parameterTypes;

	protected transient Method aspectJAdviceMethod;

View on GitHub (pinned to 69bf83ad71)