{"record":{"id":"fb1abfa91624d97e","repo":"alibaba/spring-ai-alibaba","slug":"cannot-instantiate-class-for-class-deserializa","errorCode":null,"errorMessage":"Cannot instantiate class {} for @class deserialization","messagePattern":"Cannot instantiate class (.+?) for @class deserialization","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/serializer/plain_text/jackson/JacksonDeserializer.java","lineNumber":313,"sourceCode":"\t\t\t\t\tcopy.remove(\"@typeHint\");\n\t\t\t\t\t\n\t\t\t\t\t// Get Class from TypeReference using ObjectMapper's TypeFactory\n\t\t\t\t\tClass<?> targetClass = objectMapper.getTypeFactory().constructType(ref).getRawClass();\n\t\t\t\t\tyield deserializeWithStrategy(copy, targetClass, objectMapper, typeMapper);\n\t\t\t\t}\n\t\t\t\tif (valueNode.has(\"@class\")) {\n\t\t\t\t\tString className = valueNode.get(\"@class\").asText();\n\t\t\t\t\tif (!(typeHint != null && className.startsWith(\"java.util.\"))) {\n\t\t\t\t\tObjectNode copy = valueNode.deepCopy();\n\t\t\t\t\tcopy.remove(\"@class\");\n\t\t\t\t\tcopy.remove(\"@typeHint\");\n\t\t\t\t\ttry {\n\t\t\t\t\t\tClass<?> clazz = Class.forName(className);\n\t\t\t\t\t\t// Use unified deserialization strategy\n\t\t\t\t\t\tyield deserializeWithStrategy(copy, clazz, objectMapper, typeMapper);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ClassNotFoundException ex) {\n\t\t\t\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\t\t\t\"Cannot instantiate class \" + className + \" for @class deserialization\", ex);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (typeHint != null) {\n\t\t\t\t\tObjectNode copy = valueNode.deepCopy();\n\t\t\t\t\tcopy.remove(\"@typeHint\");\n\t\t\t\t\tcopy.remove(TYPE_PROPERTY);\n\t\t\t\t\tcopy.remove(\"@class\");\n\t\t\t\t\ttry {\n\t\t\t\t\t\tClass<?> clazz = Class.forName(typeHint);\n\t\t\t\t\t\t// Use unified deserialization strategy\n\t\t\t\t\t\tyield deserializeWithStrategy(copy, clazz, objectMapper, typeMapper);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ClassNotFoundException ex) {\n\t\t\t\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\t\t\t\"Cannot instantiate class \" + typeHint + \" for @typeHint deserialization\", ex);\n\t\t\t\t\t}","sourceCodeStart":295,"sourceCodeEnd":331,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/serializer/plain_text/jackson/JacksonDeserializer.java#L295-L331","documentation":"JacksonDeserializer.valueFromNode resolves a @class type hint in the JSON via Class.forName(className); if the class is not on the classpath, it wraps the ClassNotFoundException in an IllegalStateException(\"Cannot instantiate class <name> for @class deserialization\"). This prevents silently degrading typed data to maps when the declared type is unavailable.","triggerScenarios":"Deserializing JSON produced elsewhere (another JVM, persisted checkpoint, studio/admin export) whose @class field names a class missing from the current application's classpath.","commonSituations":"Renamed/moved/removed classes after refactor; checkpoint saved by an older library version; missing dependency jar containing the class; serializing application-specific classes then deserializing in a different module.","solutions":["Add the jar/dependency containing the named class to the classpath","Restore the original package/class name or keep a compatibility class during migration","Re-serialize checkpoints with current classes, or delete old checkpoints","Ensure both producer and consumer use the same spring-ai-alibaba versions"],"exampleFix":"// before\n// checkpoint written by com.old.pkg.MyState (class since moved)\nObject v = deserializer.valueFromNode(node); // IllegalStateException\n// after\n// keep a backwards-compatible alias or migrate the stored @class value\n// old: \"@class\":\"com.old.pkg.MyState\"\n// new: \"@class\":\"com.new.pkg.MyState\"","handlingStrategy":"try-catch","validationCode":"// before deserializing, check the @class is resolvable\nString className = valueNode.get(\"@class\").asText();\ntry {\n    Class.forName(className);\n} catch (ClassNotFoundException e) {\n    logger.warn(\"@class {} missing from classpath\", className);\n}","typeGuard":"boolean classResolvable(String name) {\n    try { Class.forName(name); return true; }\n    catch (ClassNotFoundException e) { return false; }\n}","tryCatchPattern":"try {\n    return deserializer.valueFromNode(node);\n} catch (IllegalStateException e) {\n    if (String.valueOf(e.getMessage()).contains(\"for @class deserialization\")) {\n        // fall back to raw map or rebuild state from defaults\n        return objectMapper.convertValue(node, new TypeReference<Map<String,Object>>() {});\n    }\n    throw e;\n}","preventionTips":["Keep DTO classes referenced in @class hints in a shared dependency","Never rename/move classes referenced by persisted checkpoints without migration","Align library versions between services exchanging serialized state","Validate @class values against an allowlist at load time"],"tags":["deserialization","classnotfound","jackson","classpath"],"backgroundTag":"class-not-found","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"}