{"record":{"id":"e40c15ab1f564990","repo":"alibaba/spring-ai-alibaba","slug":"cannot-instantiate-array-type-from-scalar-payload","errorCode":null,"errorMessage":"Cannot instantiate array type from scalar payload: {}","messagePattern":"Cannot instantiate array type from scalar payload: (.+?)","errorType":"exception","errorClass":"IOException","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":512,"sourceCode":"\t * Reconstruct a primitive array that Jackson's WRAPPER_ARRAY default typing serialized\n\t * with a scalar (non-array) payload. Notably {@code byte[]} is written as a base64\n\t * string and {@code char[]} as a plain string. Delegating to Jackson preserves the\n\t * exact array type so values such as Gemini {@code thoughtSignatures} ({@code List<byte[]>})\n\t * survive a serialize/clone round-trip.\n\t * @param className the serialized component type id (e.g. {@code [B} or {@code byte[]})\n\t * @param payload the scalar payload node\n\t * @param objectMapper the ObjectMapper to bind with\n\t * @return the reconstructed array\n\t * @throws IOException if binding fails\n\t */\n\tprivate static Object instantiateScalarPayloadArray(String className, JsonNode payload, ObjectMapper objectMapper)\n\t\t\tthrows IOException {\n\t\ttry {\n\t\t\tClass<?> arrayClass = resolveArrayClass(className);\n\t\t\treturn objectMapper.treeToValue(payload, arrayClass);\n\t\t}\n\t\tcatch (ClassNotFoundException | IllegalArgumentException ex) {\n\t\t\tthrow new IOException(\"Cannot instantiate array type from scalar payload: \" + className, ex);\n\t\t}\n\t}\n\n\tprivate static Class<?> resolveArrayClass(String className) throws ClassNotFoundException {\n\t\tif (className.startsWith(\"[\")) {\n\t\t\treturn Class.forName(className);\n\t\t}\n\t\tif (!className.endsWith(\"[]\")) {\n\t\t\tthrow new ClassNotFoundException(\"Unsupported array type representation: \" + className);\n\t\t}\n\t\tString componentName = className.substring(0, className.length() - 2);\n\t\treturn switch (componentName) {\n\t\t\tcase \"boolean\" -> boolean[].class;\n\t\t\tcase \"byte\" -> byte[].class;\n\t\t\tcase \"char\" -> char[].class;\n\t\t\tcase \"short\" -> short[].class;\n\t\t\tcase \"int\" -> int[].class;\n\t\t\tcase \"long\" -> long[].class;","sourceCodeStart":494,"sourceCodeEnd":530,"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#L494-L530","documentation":"When a primitive array (notably byte[]) was serialized by Jackson's WRAPPER_ARRAY default typing with a scalar payload, the deserializer tries to convert that scalar tree directly to the array type. Conversion fails if the payload cannot be coerced into the array class, or the class name cannot be resolved, so an IOException is thrown wrapping the cause.","triggerScenarios":"deserializeArrayNode -> instantiateScalarArray: payload JSON node is a scalar (e.g. base64 string) but treeToValue cannot convert it to the resolved array class, or resolveArrayClass throws ClassNotFoundException.","commonSituations":"Manually edited or tool-mutated serialized state where the base64 string was replaced by a non-coercible value; version drift between serializer and deserializer formats; passing an array type name that resolveArrayClass does not understand.","solutions":["Verify the scalar payload matches what the serializer wrote (base64 string for byte[]) and restore the original serialized content","Ensure the className is a valid array representation ('byte[]', '[B', etc.) that resolveArrayClass can map","Re-persist the state with the current library version so the payload format matches","Catch IOException during state load and fall back to re-executing the graph from a fresh checkpoint"],"exampleFix":"// before: hand-edited checkpoint\n{\"type\":\"byte[]\",\"value\":12345}\n// after: keep the base64 scalar payload the serializer produced\n{\"type\":\"byte[]\",\"value\":\"AQIDBA==\"}","handlingStrategy":"validation","validationCode":"if (!node.isString() && !node.isArray()) throw new IOException(\"Unexpected scalar payload for array type \" + className);","typeGuard":"boolean isCoercibleToArray(JsonNode payload, Class<?> arrayClass) {\n    try { objectMapper.treeToValue(payload, arrayClass); return true; } catch (Exception e) { return false; }\n}","tryCatchPattern":"try { value = deserializer.readState(in); } catch (IOException e) { if (e.getMessage().contains(\"scalar payload\")) { /* restore from source-of-truth store */ } else throw e; }","preventionTips":["Never hand-edit serialized checkpoints; regenerate them programmatically","Pin the library version used to write state and use the same version to read it","Log and quarantine unreadable checkpoints instead of failing the whole workflow"],"tags":["deserialization","jackson","type-coercion"],"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"}