spring-projects/spring-ai · error · RuntimeException

Failed to serialize

Error message

Failed to serialize

What it means

serializeToBytes() serializes id-content objects with Java ObjectOutputStream to hash them; any failure (NotSerializableException, IOException on the internal ByteArrayOutputStream) is wrapped in RuntimeException('Failed to serialize'). Since ByteArrayOutputStream can't actually throw IOException, real failures are almost always non-serializable content passed to generate().

Solutions

  1. Ensure every object passed to generate() is fully Serializable (including nested values)
  2. Convert content to a String/byte[] yourself and hash deterministically instead of relying on Java serialization
  3. Inspect the wrapped cause (NotSerializableException names the offending class)
  4. Use a different IdGenerator (e.g. RandomIdGenerator) if content isn't serializable

Example fix

// before
String id = idGenerator.generate(document.getMetadata()); // metadata holds non-serializable values
// after
String id = idGenerator.generate(String.valueOf(document.getMetadata())); // plain String, always serializable
Defensive patterns

Strategy: validation

Validate before calling

// ensure content is serializable before hashing
if (!(content instanceof java.io.Serializable)) {
    content = String.valueOf(content);
}

Type guard

static Object requireSerializable(Object o) {
    return o instanceof java.io.Serializable ? o : String.valueOf(o);
}

Try / catch

try {
    id = gen.generate(content);
} catch (RuntimeException e) {
    if (e.getMessage() != null && e.getMessage().contains("Failed to serialize")) {
        id = gen.generate(String.valueOf(content));
    } else throw e;
}

Prevention

When it happens

Trigger: Calling jdkSha256HexIdGenerator.generate(obj) where obj (or a nested field) does not implement java.io.Serializable, e.g. a Document whose metadata holds a lambda, streams, or third-party non-serializable types.

Common situations: Hashing documents with metadata maps containing ObjectMapper instances, InputStreams, or lambdas captured from method references.

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11). Data as JSON: /api/errors/e7d3a886147aa931. Report an issue: GitHub.

Appendix: source

Thrown at spring-ai-commons/src/main/java/org/springframework/ai/document/id/JdkSha256HexIdGenerator.java:84

		byte[] hashBytes = getMessageDigest().digest(contentWithMetadata);
		StringBuilder sb = new StringBuilder();
		for (byte b : hashBytes) {
			sb.append(String.format(this.byteHexFormat, b));
		}
		return UUID.nameUUIDFromBytes(sb.toString().getBytes(this.charset)).toString();
	}

	private byte[] serializeToBytes(Object... contents) {
		Assert.notNull(contents, "Contents must not be null");
		try (ByteArrayOutputStream byteOut = new ByteArrayOutputStream()) {
			ObjectOutputStream out = new ObjectOutputStream(byteOut);
			for (Object content : contents) {
				out.writeObject(content);
			}
			return byteOut.toByteArray();
		}
		catch (Exception e) {
			throw new RuntimeException("Failed to serialize", e);
		}
	}

	MessageDigest getMessageDigest() {
		try {
			return (MessageDigest) this.messageDigest.clone();
		}
		catch (CloneNotSupportedException e) {
			throw new RuntimeException("Unsupported clone for MessageDigest.", e);
		}
	}

}

View on GitHub (pinned to 98a7beda4f)