{"record":{"id":"98351955e6e545c0","repo":"alibaba/spring-ai-alibaba","slug":"failed-to-deserialize-checkpoints","errorCode":null,"errorMessage":"Failed to deserialize checkpoints","messagePattern":"Failed to deserialize checkpoints","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/checkpoint/savers/redis/RedisSaver.java","lineNumber":254,"sourceCode":"\t\t\tif (!tryLock) {\n\t\t\t\treturn List.of();\n\t\t\t}\n\n\t\t\t// Get active thread_id for the thread_name\n\t\t\tString threadId = getActiveThreadId(threadName);\n\t\t\tif (threadId == null) {\n\t\t\t\treturn List.of();\n\t\t\t}\n\n\t\t\t// Use thread_id to query checkpoints\n\t\t\treturn deserializeCheckpoints(CHECKPOINT_PREFIX + threadId);\n\n\t\t}\n\t\tcatch (InterruptedException e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t\tcatch (IOException | ClassNotFoundException e) {\n\t\t\tthrow new RuntimeException(\"Failed to deserialize checkpoints\", e);\n\t\t}\n\t\tfinally {\n\t\t\tif (lock.isHeldByCurrentThread()) {\n\t\t\t\tlock.unlock();\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic Optional<Checkpoint> get(RunnableConfig config) {\n\t\tOptional<String> threadNameOpt = config.threadId();\n\t\tif (!threadNameOpt.isPresent()) {\n\t\t\tthrow new IllegalArgumentException(\"threadId isn't allow null\");\n\t\t}\n\n\t\tString threadName = threadNameOpt.get();\n\t\tRLock lock = redisson.getLock(LOCK_PREFIX + threadName);\n\t\tboolean tryLock = false;","sourceCodeStart":236,"sourceCodeEnd":272,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/checkpoint/savers/redis/RedisSaver.java#L236-L272","documentation":"RedisSaver.list catches IOException | ClassNotFoundException thrown by deserializeCheckpoints and rethrows them as RuntimeException('Failed to deserialize checkpoints'). It means raw checkpoint bytes read from Redis could not be deserialized back into Checkpoint objects — typically a serialization format or classpath mismatch.","triggerScenarios":"Checkpoints written by a different serializer version or different StateSerializer (e.g. JDK vs Jackson), state classes that changed package/name after a refactor, or corrupted/stale Redis keys from an older app version.","commonSituations":"Upgrading the app or spring-ai-alibaba version while old checkpoints persist in Redis; serialVersionUID changes on custom state objects; switching StateGraph serializer between runs; manual Redis data migrations.","solutions":["Check the chained cause for ClassNotFoundException — restore or add the missing class/version to the classpath.","Flush stale checkpoints for affected threads (delete CHECKPOINT_PREFIX + threadId keys) and let the graph recreate them.","Use the same StateSerializer consistently across all writers and readers of the same Redis database.","Pin a stable serialVersionUID (or switch to JSON serialization) for custom state classes to survive refactors."],"exampleFix":"// before\nStateSerializer serializer = new JDKStateSerializer<>(stateFactory); // was Jackson before\n// after\nStateSerializer serializer = StateGraph.DEFAULT_JACKSON_SERIALIZER; // match writer's serializer\n// and/or clear stale keys: redisTemplate.delete(\"checkpoints:\" + threadId);","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { return saver.list(config); } catch (RuntimeException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"Failed to deserialize\")) {\n        log.warn(\"Incompatible stale checkpoints; starting fresh\", e);\n        return List.of(); // or purge keys and continue\n    }\n    throw e;\n}","preventionTips":["Keep one StateSerializer across versions","Fix serialVersionUID on custom state classes","Purge Redis checkpoint keys on incompatible upgrades","Test deserialization of persisted checkpoints in CI"],"tags":["redis","serialization","deserialization","checkpoint","versioning"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}