alibaba/spring-ai-alibaba · error · IOException
Cannot instantiate array type from scalar payload: {}
Error message
Cannot instantiate array type from scalar payload: {} What it means
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.
Source
Thrown at spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/serializer/plain_text/jackson/JacksonDeserializer.java:512
* Reconstruct a primitive array that Jackson's WRAPPER_ARRAY default typing serialized
* with a scalar (non-array) payload. Notably {@code byte[]} is written as a base64
* string and {@code char[]} as a plain string. Delegating to Jackson preserves the
* exact array type so values such as Gemini {@code thoughtSignatures} ({@code List<byte[]>})
* survive a serialize/clone round-trip.
* @param className the serialized component type id (e.g. {@code [B} or {@code byte[]})
* @param payload the scalar payload node
* @param objectMapper the ObjectMapper to bind with
* @return the reconstructed array
* @throws IOException if binding fails
*/
private static Object instantiateScalarPayloadArray(String className, JsonNode payload, ObjectMapper objectMapper)
throws IOException {
try {
Class<?> arrayClass = resolveArrayClass(className);
return objectMapper.treeToValue(payload, arrayClass);
}
catch (ClassNotFoundException | IllegalArgumentException ex) {
throw new IOException("Cannot instantiate array type from scalar payload: " + className, ex);
}
}
private static Class<?> resolveArrayClass(String className) throws ClassNotFoundException {
if (className.startsWith("[")) {
return Class.forName(className);
}
if (!className.endsWith("[]")) {
throw new ClassNotFoundException("Unsupported array type representation: " + className);
}
String componentName = className.substring(0, className.length() - 2);
return switch (componentName) {
case "boolean" -> boolean[].class;
case "byte" -> byte[].class;
case "char" -> char[].class;
case "short" -> short[].class;
case "int" -> int[].class;
case "long" -> long[].class;View on GitHub (pinned to f82da0b50f)
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
Example fix
// before: hand-edited checkpoint
{"type":"byte[]","value":12345}
// after: keep the base64 scalar payload the serializer produced
{"type":"byte[]","value":"AQIDBA=="} Defensive patterns
Strategy: validation
Validate before calling
if (!node.isString() && !node.isArray()) throw new IOException("Unexpected scalar payload for array type " + className); Type guard
boolean isCoercibleToArray(JsonNode payload, Class<?> arrayClass) {
try { objectMapper.treeToValue(payload, arrayClass); return true; } catch (Exception e) { return false; }
} Try / catch
try { value = deserializer.readState(in); } catch (IOException e) { if (e.getMessage().contains("scalar payload")) { /* restore from source-of-truth store */ } else throw e; } Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
- Status value cannot be null
- Unknown status: ${value}. Valid values are: pending, in_prog
- Cannot instantiate class {} for @class deserialization
- Cannot instantiate class {} for @typeHint deserialization
- Failed to deserialize store item
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/e40c15ab1f564990.
Report an issue: GitHub.