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

  1. Verify the scalar payload matches what the serializer wrote (base64 string for byte[]) and restore the original serialized content
  2. Ensure the className is a valid array representation ('byte[]', '[B', etc.) that resolveArrayClass can map
  3. Re-persist the state with the current library version so the payload format matches
  4. 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

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


AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09). Data as JSON: /api/errors/e40c15ab1f564990. Report an issue: GitHub.