spring-projects/spring-framework · error · IllegalStateException
Cannot find current proxy: Set 'exposeProxy' property on Adv
Error message
Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available, and ensure that AopContext.currentProxy() is invoked in the same thread as the AOP invocation context.
What it means
Thrown by AopContext.currentProxy() when the per-thread ThreadLocal holding the current AOP proxy is null. Spring does not expose the proxy by default (performance cost); it only populates the ThreadLocal when ProxyConfig.exposeProxy=true. The error means either exposeProxy was not enabled, or currentProxy() was called from a different thread than the one running the AOP invocation (the ThreadLocal is set/restored around the proxy invocation only).
Source
Thrown at spring-aop/src/main/java/org/springframework/aop/framework/AopContext.java:70
private AopContext() {
}
/**
* Try to return the current AOP proxy. This method is usable only if the
* calling method has been invoked via AOP, and the AOP framework has been set
* to expose proxies. Otherwise, this method will throw an IllegalStateException.
* @return the current AOP proxy (never returns {@code null})
* @throws IllegalStateException if the proxy cannot be found, because the
* method was invoked outside an AOP invocation context, or because the
* AOP framework has not been configured to expose the proxy
*/
public static Object currentProxy() throws IllegalStateException {
Object proxy = currentProxy.get();
if (proxy == null) {
throw new IllegalStateException(
"Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available, and " +
"ensure that AopContext.currentProxy() is invoked in the same thread as the AOP invocation context.");
}
return proxy;
}
/**
* Make the given proxy available via the {@code currentProxy()} method.
* <p>Note that the caller should be careful to keep the old value as appropriate.
* @param proxy the proxy to expose (or {@code null} to reset it)
* @return the old proxy, which may be {@code null} if none was bound
* @see #currentProxy()
*/
static @Nullable Object setCurrentProxy(@Nullable Object proxy) {
Object old = currentProxy.get();
if (proxy != null) {
currentProxy.set(proxy);
}View on GitHub (pinned to e8729d0438)
Solutions
- Enable exposeProxy on the proxy config: <aop:aspectj-autoproxy expose-proxy="true"/> or @EnableAspectJAutoProxy(exposeProxy=true), or ProxyConfig.setExposeProxy(true).
- Avoid the pattern entirely by injecting the proxy/self reference into the bean and calling through it, or refactor self-invocation into a separate bean.
- Ensure currentProxy() is called synchronously within the same thread and stack frame as the proxied method body.
- For async/reactive flows, capture the proxy before switching threads and pass it explicitly, since the ThreadLocal will not transfer.
Example fix
// before @Configuration @EnableAspectJAutoProxy // ... in target code AopContext.currentProxy(); // throws // after @Configuration @EnableAspectJAutoProxy(exposeProxy = true) // ... in target code, same thread as the proxied call MyService self = (MyService) AopContext.currentProxy(); self.otherTransactionalMethod();
Defensive patterns
Strategy: validation
Validate before calling
// Verify before invoking, in the same thread as the proxied call: Object proxy = AopContext.currentProxy(); // will throw if not exposed; guard instead: boolean exposed = ...; // from @EnableAspectJAutoProxy(exposeProxy=true) // Prefer: inject the proxy bean reference and avoid AopContext entirely.
Try / catch
try {
Object proxy = AopContext.currentProxy();
} catch (IllegalStateException ex) {
// exposeProxy not set, or wrong thread; fall back to injected self reference
} Prevention
- Enable exposeProxy globally only if self-invocation-through-proxy is unavoidable; otherwise inject the proxy bean.
- Never call currentProxy() from a different thread/reactive scheduler than the AOP invocation.
- Capture the proxy before async hand-off and pass it explicitly.
When it happens
Trigger: Calling AopContext.currentProxy() from target code when exposeProxy=false; calling it from a newly-spawned thread, a CompletableFuture/scheduler, or after the original invocation returned; calling it outside any proxied method invocation at all.
Common situations: Self-invocation of an advised method where the developer wants the proxy (e.g. to hit @Transactional on another method of the same bean); async hand-off to another thread loses the ThreadLocal; reactive/reactor pipelines where the continuation runs on a different thread.
Related errors
- No MethodInvocation found: Check that an AOP invocation is i
- MethodInvocation is not a Spring ProxyMethodInvocation: {}
- 'argumentNames' property of AbstractAspectJAdvice contains a
- Only afterReturning advice can be used to bind a return valu
- Returning name '{}' is neither a valid argument name nor the
AI-assisted analysis of spring-projects/spring-framework@e8729d0438 (2026-08-04).
Data as JSON: /data/errors/8e6388b210507ee1.json.
Report an issue: GitHub.