{"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/e8729d043887bf0d0baf91e062e909b56eb2b708/spring-aop/src/main/java/org/springframework/aop/support/AopUtils.java#L136-L172","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Change the method's visibility to package-private or protected (or public).","Move cross-cutting logic off private methods: extract to a public advised bean.","Do not rely on Spring AOP to intercept private methods (use AspectJ weaving if truly needed)."],"exampleFix":"// before\npublic class Service {\n  @Transactional\n  private void updateDb() { ... } // -> error 113 when proxied\n}\n\n// after\npublic class Service {\n  @Transactional\n  protected void updateDb() { ... }\n}","handlingStrategy":"validation","validationCode":"import java.lang.reflect.Modifier;\nboolean safelyProxies(Method m) {\n    return !Modifier.isPrivate(m.getModifiers()) || Modifier.isStatic(m.getModifiers());\n}","typeGuard":"boolean isAdvisableMethod(java.lang.reflect.Method m) {\n    int mod = m.getModifiers();\n    return !Modifier.isPrivate(mod) && !Modifier.isStatic(mod);\n}","tryCatchPattern":null,"preventionTips":["Keep advised methods package-private or wider.","Never annotate private methods with Spring AOP advice annotations.","Use AspectJ weaving if private-method interception is truly required."],"tags":["spring-aop","proxy","visibility","cglib","private-method"],"analyzedSha":"e8729d043887bf0d0baf91e062e909b56eb2b708","analyzedAt":"2026-08-04T19:07:39.725Z","schemaVersion":2}