{"record":{"id":"fc591757fc0bd1c0","repo":"spring-projects/spring-framework","slug":"need-to-invoke-method-s-found-on-proxy-for-targ","errorCode":null,"errorMessage":"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.","messagePattern":"Need to invoke method '(.+?)' found on proxy for target class '(.+?)' but cannot be delegated to target bean\\. Switch its visibility to package or protected\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/support/AopUtils.java","lineNumber":154,"sourceCode":"\t * Select an invocable method on the target type: either the given method itself\n\t * if actually exposed on the target type, or otherwise a corresponding method\n\t * on one of the target type's interfaces or on the target type itself.\n\t * @param method the method to check\n\t * @param targetType the target type to search methods on (typically an AOP proxy)\n\t * @return a corresponding invocable method on the target type\n\t * @throws IllegalStateException if the given method is not invocable on the given\n\t * target type (typically due to a proxy mismatch)\n\t * @since 4.3\n\t * @see MethodIntrospector#selectInvocableMethod(Method, Class)\n\t */\n\tpublic static Method selectInvocableMethod(Method method, @Nullable Class<?> targetType) {\n\t\tif (targetType == null) {\n\t\t\treturn method;\n\t\t}\n\t\tMethod methodToUse = MethodIntrospector.selectInvocableMethod(method, targetType);\n\t\tif (Modifier.isPrivate(methodToUse.getModifiers()) && !Modifier.isStatic(methodToUse.getModifiers()) &&\n\t\t\t\tSpringProxy.class.isAssignableFrom(targetType)) {\n\t\t\tthrow new IllegalStateException(String.format(\n\t\t\t\t\t\"Need to invoke method '%s' found on proxy for target class '%s' but cannot \" +\n\t\t\t\t\t\"be delegated to target bean. Switch its visibility to package or protected.\",\n\t\t\t\t\tmethod.getName(), method.getDeclaringClass().getSimpleName()));\n\t\t}\n\t\treturn methodToUse;\n\t}\n\n\t/**\n\t * Determine whether the given method is an \"equals\" method.\n\t * @see java.lang.Object#equals\n\t */\n\tpublic static boolean isEqualsMethod(@Nullable Method method) {\n\t\treturn ReflectionUtils.isEqualsMethod(method);\n\t}\n\n\t/**\n\t * Determine whether the given method is a \"hashCode\" method.\n\t * @see java.lang.Object#hashCode","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/69bf83ad716d0cfc4b0520a19b4d8b24c79d1538/spring-aop/src/main/java/org/springframework/aop/support/AopUtils.java#L136-L172","documentation":"Thrown by AopUtils.selectInvocableMethod (line 152-158) when the method selected for invocation is private and non-static and the target type is a SpringProxy (a CGLIB-based AOP proxy). CGLIB subclasses the target and cannot override or delegate private methods to the actual target instance, so the call would execute on the proxy subclass rather than the real bean; Spring therefore rejects it with an IllegalStateException and asks you to widen visibility.","triggerScenarios":"Invoking a private method on a bean that gets class-based (CGLIB) proxied - e.g. a private @Transactional, @Async, or other advised method, or programmatic AOP selecting a private method via selectInvocableMethod. Also triggered when introspection resolves an advised joinpoint to a private method on the proxy subclass.","commonSituations":"Making a @Transactional or @Async method private (Spring AOP cannot intercept private methods). Refactoring a public method to package/private by mistake. Using class-based proxying (proxyTargetClass=true) on beans with private advised methods.","solutions":["Change the method visibility from private to package-private or protected (public also works) so CGLIB can override and delegate it.","Move the cross-cutting concern to a public method and have the private helper call it, or use AspectJ load-time weaving (which can advise private methods) instead of Spring proxy-based AOP.","Ensure proxyTargetClass is intentional; interface-based (JDK dynamic) proxies avoid CGLIB private-method issues but cannot proxy non-interface methods at all."],"exampleFix":"// before\n@Service\npublic class OrderService {\n    @Transactional\n    private void save(Order o) { /* ... */ } // CGLIB cannot delegate\n}\n\n// after\n@Service\npublic class OrderService {\n    @Transactional\n    protected void save(Order o) { /* ... */ }\n}","handlingStrategy":"validation","validationCode":"import java.lang.reflect.Modifier;\nstatic boolean aopInvocable(Method m, Class<?> targetType) {\n    int mod = m.getModifiers();\n    return !Modifier.isPrivate(mod) || Modifier.isStatic(mod)\n        || !org.springframework.aop.SpringProxy.class.isAssignableFrom(targetType);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep advised (proxied) methods package-private, protected, or public.","Do not put @Transactional/@Async on private methods with proxy-based AOP.","Use AspectJ weaving if you truly need to advise private methods."],"tags":["spring-aop","cglib","proxy","visibility","reflection"],"backgroundTag":null,"analyzedSha":"69bf83ad716d0cfc4b0520a19b4d8b24c79d1538","analyzedAt":"2026-08-09T15:32:58.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}