{"record":{"id":"9478f401ecb676db","repo":"spring-projects/spring-framework","slug":"failed-to-find-advice-method-on-deserialization-9478f4","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/annotation/InstantiationModelAwarePointcutAdvisorImpl.java","lineNumber":246,"sourceCode":"\t\t\t\t\tthis.isBeforeAdvice = true;\n\t\t\t\t\tthis.isAfterAdvice = false;\n\t\t\t\t}\n\t\t\t\tcase AtAfter, AtAfterReturning, AtAfterThrowing -> {\n\t\t\t\t\tthis.isBeforeAdvice = false;\n\t\t\t\t\tthis.isAfterAdvice = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\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\t@Override\n\tpublic String toString() {\n\t\treturn \"InstantiationModelAwarePointcutAdvisor: expression [\" + getDeclaredPointcut().getExpression() +\n\t\t\t\t\"]; advice method [\" + this.aspectJAdviceMethod + \"]; perClauseKind=\" +\n\t\t\t\tthis.aspectInstanceFactory.getAspectMetadata().getAjType().getPerClause().getKind();\n\t}\n\n\n\t/**\n\t * Pointcut implementation that changes its behavior when the advice is instantiated.\n\t * Note that this is a <i>dynamic</i> pointcut; otherwise it might be optimized out\n\t * if it does not at first match statically.\n\t */\n\tprivate static final class PerTargetInstantiationModelPointcut extends DynamicMethodMatcherPointcut {\n","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/69bf83ad716d0cfc4b0520a19b4d8b24c79d1538/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/InstantiationModelAwarePointcutAdvisorImpl.java#L228-L264","documentation":"Thrown as an IllegalStateException from InstantiationModelAwarePointcutAdvisorImpl.readObject() during deserialization of a serialized aspect advisor. On readObject, Spring re-resolves the advice Method via declaringClass.getMethod(methodName, parameterTypes); a NoSuchMethodException means the advice method no longer exists on the declaring class (renamed, signature changed, removed, or the class was replaced) between serialization and deserialization.","triggerScenarios":"Serializing a proxied object whose advisor chain contains an InstantiationModelAwarePointcutAdvisorImpl, then deserializing it in a JVM/version where the aspect class's advice method has been renamed, had its parameter list changed, or was deleted. Also possible with classloader differences that resolve declaringClass to a different version.","commonSituations":"Distributing a serialized proxy to a node running a different application version; HTTP session or cache replication of proxied beans across nodes with mismatched aspect bytecode; hot-reloading that changes advice method signatures while a proxy is cached.","solutions":["Ensure the aspect class bytecode (method name and parameter types) is identical on both the serializing and deserializing sides; align application versions.","Avoid serializing Spring AOP proxies; serialize the underlying data and re-obtain the proxied bean from the target context.","If proxies must be serialized, mark the relevant advice methods stable (do not rename/change signatures across releases)."],"exampleFix":"// before\n// Node A (v1): aspect has log(java.lang.String)\n// Node B (v2): aspect renamed method to logMessage(java.lang.String)\n// deserializing a proxy from A on B throws\n\n// after\n// Keep the advice method signature stable across versions:\n@AfterReturning(\"execution(* com.example..*.*(..))\")\npublic void log(JoinPoint jp) { ... } // unchanged name+params on both nodes","handlingStrategy":"validation","validationCode":"// Before deserializing a proxy, verify the advice method still exists:\npublic static boolean adviceMethodExists(Class<?> declaringClass, String methodName, Class<?>[] paramTypes) {\n    try {\n        declaringClass.getMethod(methodName, paramTypes);\n        return true;\n    } catch (NoSuchMethodException e) {\n        return false;\n    }\n}\n\nif (!adviceMethodExists(aspectClass, \"log\", new Class<?>[]{JoinPoint.class})) {\n    throw new IllegalStateException(\"Aspect advice method missing; cannot deserialize proxy safely\");\n}","typeGuard":null,"tryCatchPattern":"try (ObjectInputStream ois = new ObjectInputStream(in)) {\n    Object proxy = ois.readObject();\n} catch (IllegalStateException ex) {\n    if (ex.getCause() instanceof NoSuchMethodException) {\n        // rebuild the proxy locally instead of deserializing\n    } else throw ex;\n}","preventionTips":["Avoid serializing Spring AOP proxies; serialize DTOs and re-resolve beans on the other side.","Keep advice method names and parameter types stable across releases that exchange serialized proxies.","Pin application versions on nodes that share serialized session/cache data containing proxies."],"tags":["spring-aop","serialization","versioning","aspectj"],"backgroundTag":null,"analyzedSha":"69bf83ad716d0cfc4b0520a19b4d8b24c79d1538","analyzedAt":"2026-08-09T15:32:58.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}