{"record":{"id":"bff89e43a6d16c60","repo":"spring-projects/spring-framework","slug":"failed-to-find-advice-method-on-deserialization","errorCode":null,"errorMessage":"Failed to find advice method on deserialization","messagePattern":"Failed to find advice method on deserialization","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java","lineNumber":702,"sourceCode":"\tprotected @Nullable JoinPointMatch getJoinPointMatch(ProxyMethodInvocation pmi) {\n\t\tString expression = this.pointcut.getExpression();\n\t\treturn (expression != null ? (JoinPointMatch) pmi.getUserAttribute(expression) : null);\n\t}\n\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getClass().getName() + \": advice method [\" + this.aspectJAdviceMethod + \"]; \" +\n\t\t\t\t\"aspect name '\" + this.aspectName + \"'\";\n\t}\n\n\tprivate void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException {\n\t\tinputStream.defaultReadObject();\n\t\ttry {\n\t\t\tthis.aspectJAdviceMethod = this.declaringClass.getMethod(this.methodName, this.parameterTypes);\n\t\t}\n\t\tcatch (NoSuchMethodException ex) {\n\t\t\tthrow new IllegalStateException(\"Failed to find advice method on deserialization\", ex);\n\t\t}\n\t}\n\n\n\t/**\n\t * MethodMatcher that excludes the specified advice method.\n\t * @see AbstractAspectJAdvice#buildSafePointcut()\n\t */\n\tprivate static class AdviceExcludingMethodMatcher extends StaticMethodMatcher {\n\n\t\tprivate final Method adviceMethod;\n\n\t\tpublic AdviceExcludingMethodMatcher(Method adviceMethod) {\n\t\t\tthis.adviceMethod = adviceMethod;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean matches(Method method, Class<?> targetClass) {","sourceCodeStart":684,"sourceCodeEnd":720,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/69bf83ad716d0cfc4b0520a19b4d8b24c79d1538/spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java#L684-L720","documentation":"Thrown by readObject (line 696-704) during Java deserialization of an AbstractAspectJAdvice subclass. The method is marked transient (line 100) so on deserialization Spring re-looks-up the advice Method via declaringClass.getMethod(methodName, parameterTypes). If that lookup throws NoSuchMethodException, the aspect's bytecode no longer matches what was serialized.","triggerScenarios":"Serializing an aspect/advice in one deployment and deserializing in another where the aspect class was renamed, its method was renamed/signature changed, or the class version differs. Also if the declaring class is loaded by a different ClassLoader that does not see the method.","commonSituations":"Distributing serialized proxies across JVMs (e.g. via Spring HTTP Invoker, RMI, or a cache), redeploying with a refactored aspect, hot-swapping jars without re-serializing, or ClassLoader isolation between the serializer and deserializer.","solutions":["Ensure the aspect class (same fully-qualified name, same method name and parameter types) is on the classpath of the deserializing JVM.","Do not serialize Spring AOP proxies across versions; rebuild the proxy on the receiving side instead.","If the aspect method changed, re-serialize after the change so the methodName/parameterTypes fields match.","Use the same ClassLoader hierarchy on both ends, or avoid serializing advice objects entirely."],"exampleFix":"// before — serializing a proxied bean across a redeploy that renamed the advice method\nObjectOutputStream out = ...; out.writeObject(proxy); // method was 'logBefore'\n// redeploy renames method to 'auditBefore' -> deserialization fails\n\n// after — rebuild the proxy on the receiving JVM instead of serializing advice objects\nMyService proxy = new AspectJProxyFactory(target).addAspect(auditAspect).getProxy();","handlingStrategy":"validation","validationCode":"import java.lang.reflect.Method;\n\n// Before deserializing, confirm the advice method still exists with the same signature.\nboolean adviceMethodResolvable(Class<?> declaringClass, String methodName, Class<?>[] paramTypes) {\n    try {\n        Method m = declaringClass.getMethod(methodName, paramTypes);\n        return m != null;\n    } catch (NoSuchMethodException e) {\n        return false;\n    }\n}","typeGuard":"boolean adviceMethodExists(Class<?> declaringClass, String methodName, Class<?>[] paramTypes) {\n    try { declaringClass.getMethod(methodName, paramTypes); return true; }\n    catch (NoSuchMethodException e) { return false; }\n}","tryCatchPattern":"try (ObjectInputStream in = new ObjectInputStream(input)) {\n    Object proxy = in.readObject();\n} catch (IllegalStateException ex) {\n    if (ex.getMessage().contains(\"Failed to find advice method on deserialization\")) {\n        // aspect method renamed/removed; rebuild the proxy locally instead of deserializing\n    } else { throw ex; }\n}","preventionTips":["Do not serialize Spring AOP proxies across deployments; reconstruct them on each JVM.","Keep aspect class/method/parameter signatures stable across versions that share serialized forms.","Use the same ClassLoader hierarchy on both ends if serialization is unavoidable."],"tags":["spring-aop","aspectj","serialization","deserialization","classloader"],"backgroundTag":null,"analyzedSha":"69bf83ad716d0cfc4b0520a19b4d8b24c79d1538","analyzedAt":"2026-08-09T15:32:58.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}