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 AbstractAspectJAdvice.currentJoinPoint() (line 80-91) when the current AOP Alliance MethodInvocation obtained from ExposeInvocationInterceptor.currentInvocation() is not an instance of Spring's ProxyMethodInvocation. The code needs a ProxyMethodInvocation to read/set the user attribute holding the JoinPoint. This indicates the advice is executing outside a Spring-managed proxy chain or inside a non-Spring AOP runtime.

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 e8729d0438)

Solutions

  1. Ensure the target bean is proxied by Spring (obtained from the ApplicationContext, not via 'new') so the call flows through a Spring ProxyMethodInvocation.
  2. Add ExposeInvocationInterceptor to the advisor chain / proxy config (the AspectJ advice path requires it) so currentInvocation() returns the Spring proxy type.
  3. If invoking advice manually in tests, build a ReflectiveMethodInvocation via Spring's infrastructure or call the underlying aspectJAdviceMethod directly instead of currentJoinPoint().
  4. Remove any foreign interceptor that replaces Spring's MethodInvocation with a non-ProxyMethodInvocation implementation.

Example fix

// before: calling the raw aspect in a test
advice.afterReturning(retVal, mi); // mi is a plain org.aopalliance.intercept.MethodInvocation
// after: use a Spring ProxyMethodInvocation and register ExposeInvocationInterceptor
ProxyFactory pf = new ProxyFactory(target);
pf.addAdvice(ExposeInvocationInterceptor.INSTANCE);
pf.addAdvice(advice);
MyInterface proxy = (MyInterface) pf.getProxy();
proxy.businessMethod();
Defensive patterns

Strategy: validation

Validate before calling

// Before calling currentJoinPoint()-dependent advice logic, verify the invocation type.
MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
if (!(mi instanceof ProxyMethodInvocation)) {
    throw new IllegalStateException(
        "Cannot use AspectJ join-point binding outside a Spring ProxyMethodInvocation; got " + mi.getClass());
}

Type guard

// Guard any advice entry point that relies on currentJoinPoint().
private static boolean isSpringProxyInvocation(MethodInvocation mi) {
    return mi instanceof org.springframework.aop.ProxyMethodInvocation;
}

Try / catch

try {
    JoinPoint jp = AbstractAspectJAdvice.currentJoinPoint();
    // ...
} catch (IllegalStateException ex) {
    if (ex.getMessage().startsWith("MethodInvocation is not a Spring ProxyMethodInvocation")) {
        // not in a Spring proxy context; degrade gracefully or re-throw with context
        throw new IllegalStateException("Advice invoked outside Spring AOP proxy chain", ex);
    }
    throw ex;
}

Prevention

When it happens

Trigger: Calling currentJoinPoint() (directly or via an advice that delegates to it, e.g. getJoinPoint()/getJoinPointMatch()) when ExposeInvocationInterceptor.currentInvocation() returns a MethodInvocation that is not a ProxyMethodInvocation. This happens when the advice is invoked through a non-Spring proxy, a manually constructed ReflectiveMethodInvocation that is not the Spring proxy variant, or when the proxy was created by a different AOP framework.

Common situations: Mixing Spring AOP with another AOP framework (AspectJ weaving, ByteBuddy interceptors) on the same bean; manually invoking advice objects; unit-testing advice by stubbing MethodInvocation; deserializing/transporting an advice across a context that lost the ExposeInvocationInterceptor in its advice chain.

Related errors


AI-assisted analysis of spring-projects/spring-framework@e8729d0438 (2026-08-04). Data as JSON: /data/errors/a8c750e4e22e6eac.json. Report an issue: GitHub.