spring-projects/spring-framework · error · IllegalStateException

Cannot find current proxy: Set 'exposeProxy' property on…

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

AopContext.currentProxy() returns the AOP proxy bound to the current thread via a ThreadLocal that is only populated when the proxy's exposeProxy flag is true (ProxyConfig.setExposeProxy(true)). It throws IllegalStateException when the ThreadLocal is empty - either because exposeProxy was left false (the default, for performance) or because the call is made outside the AOP invocation on the same thread.

Solutions

  1. Enable proxy exposure: @EnableAspectJAutoProxy(exposeProxy = true) (Java) or <aop:aspectj-autoproxy expose-proxy="true"/> (XML)
  2. Avoid relying on currentProxy() - refactor self-invocation so the call goes through an injected proxy reference instead
  3. Ensure currentProxy() is invoked on the very thread executing the proxied method (do not hand off to another thread)

Example fix

// before
@EnableAspectJAutoProxy
// inside a proxied bean:
((MyService) AopContext.currentProxy()).internal();

// after
@EnableAspectJAutoProxy(exposeProxy = true)
((MyService) AopContext.currentProxy()).internal();
Defensive patterns

Strategy: validation

Validate before calling

// Verify exposeProxy and thread before calling:
if (((Advised) proxy).isExposeProxy()) {
  Object p = AopContext.currentProxy();
} else {
  throw new IllegalStateException("exposeProxy=false; cannot use AopContext.currentProxy()");
}

Type guard

private static boolean proxyExposureEnabled(Advised advised) {
  return advised != null && advised.isExposeProxy();
}

Try / catch

try {
  Object proxy = AopContext.currentProxy();
} catch (IllegalStateException ex) {
  // not in an AOP invocation or exposeProxy disabled - fall back to an injected proxy reference
}

Prevention

When it happens

Trigger: Code inside a proxied bean calls AopContext.currentProxy() without exposeProxy=true; calling currentProxy() from a different thread than the one running the AOP invocation (e.g. inside an @Async method or a spawned thread); calling it from code that is not running under AOP at all.

Common situations: Self-invocation through the proxy (AopContext.currentProxy().method()) attempted without enabling exposeProxy; @EnableAspectJAutoProxy(exposeProxy=true) omitted; reactive/async flows where the thread that reads currentProxy() is not the invocation thread.

Related errors


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

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