spring-projects/spring-framework · error · IllegalStateException

Need to invoke method '%s' found on proxy for target class '

Error message

Need to invoke method '%s' found on proxy for target class '%s' but cannot be delegated to target bean. Switch its visibility to package or protected.

What it means

AopUtils.selectInvocableMethod throws IllegalStateException when the method resolved on the target type is private and non-static and the target is a SpringProxy (i.e. a CGLIB subclass will be generated). CGLIB cannot delegate a private method to the target bean, so Spring refuses to proxy it and asks the developer to widen visibility.

Source

Thrown at spring-aop/src/main/java/org/springframework/aop/support/AopUtils.java:154

	 * Select an invocable method on the target type: either the given method itself
	 * if actually exposed on the target type, or otherwise a corresponding method
	 * on one of the target type's interfaces or on the target type itself.
	 * @param method the method to check
	 * @param targetType the target type to search methods on (typically an AOP proxy)
	 * @return a corresponding invocable method on the target type
	 * @throws IllegalStateException if the given method is not invocable on the given
	 * target type (typically due to a proxy mismatch)
	 * @since 4.3
	 * @see MethodIntrospector#selectInvocableMethod(Method, Class)
	 */
	public static Method selectInvocableMethod(Method method, @Nullable Class<?> targetType) {
		if (targetType == null) {
			return method;
		}
		Method methodToUse = MethodIntrospector.selectInvocableMethod(method, targetType);
		if (Modifier.isPrivate(methodToUse.getModifiers()) && !Modifier.isStatic(methodToUse.getModifiers()) &&
				SpringProxy.class.isAssignableFrom(targetType)) {
			throw new IllegalStateException(String.format(
					"Need to invoke method '%s' found on proxy for target class '%s' but cannot " +
					"be delegated to target bean. Switch its visibility to package or protected.",
					method.getName(), method.getDeclaringClass().getSimpleName()));
		}
		return methodToUse;
	}

	/**
	 * Determine whether the given method is an "equals" method.
	 * @see java.lang.Object#equals
	 */
	public static boolean isEqualsMethod(@Nullable Method method) {
		return ReflectionUtils.isEqualsMethod(method);
	}

	/**
	 * Determine whether the given method is a "hashCode" method.
	 * @see java.lang.Object#hashCode

View on GitHub (pinned to e8729d0438)

Solutions

  1. Change the method's visibility to package-private or protected (or public).
  2. Move cross-cutting logic off private methods: extract to a public advised bean.
  3. Do not rely on Spring AOP to intercept private methods (use AspectJ weaving if truly needed).

Example fix

// before
public class Service {
  @Transactional
  private void updateDb() { ... } // -> error 113 when proxied
}

// after
public class Service {
  @Transactional
  protected void updateDb() { ... }
}
Defensive patterns

Strategy: validation

Validate before calling

import java.lang.reflect.Modifier;
boolean safelyProxies(Method m) {
    return !Modifier.isPrivate(m.getModifiers()) || Modifier.isStatic(m.getModifiers());
}

Type guard

boolean isAdvisableMethod(java.lang.reflect.Method m) {
    int mod = m.getModifiers();
    return !Modifier.isPrivate(mod) && !Modifier.isStatic(mod);
}

Prevention

When it happens

Trigger: A method matcher or interface selection picks a private instance method on a class that is about to be proxied (e.g. @Transactional or @Async advised via CGLIB on a private method).

Common situations: Annotating private methods with @Transactional/@Async/@Cacheable (Spring AOP only advises non-private visible methods); Kotlin methods compiled private; refactoring a public method down to private without updating advice.

Related errors


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