spring-projects/spring-ai · error · RuntimeException

Unsupported clone for MessageDigest.

Error message

Unsupported clone for MessageDigest.

What it means

getMessageDigest() clones the generator's prototype MessageDigest so each hash computation gets fresh state; if the digest implementation does not support clone() it throws CloneNotSupportedException, wrapped in RuntimeException('Unsupported clone for MessageDigest.'). Standard SunJCE digests support cloning, so this indicates a custom or provider-specific MessageDigest.

Solutions

  1. Switch to a JDK-built-in algorithm (SHA-256) via the no-arg constructor
  2. Avoid HSM/provider-backed digests for id generation; use a software provider
  3. Create a new JdkSha256HexIdGenerator per hash instead of reusing the clone path
  4. Catch RuntimeException around generate() and fall back to a fresh instance

Example fix

// before
IdGenerator gen = new JdkSha256HexIdGenerator(hsmDigestAlgorithm, UTF_8);
// after
IdGenerator gen = new JdkSha256HexIdGenerator(); // SHA-256 from SunJCE, cloneable
Defensive patterns

Strategy: try-catch

Try / catch

try {
    id = gen.generate(content);
} catch (RuntimeException e) {
    if (e.getMessage() != null && e.getMessage().contains("Unsupported clone")) {
        id = new JdkSha256HexIdGenerator().generate(content); // software provider fallback
    } else throw e;
}

Prevention

When it happens

Trigger: Using a JdkSha256HexIdGenerator constructed with a custom algorithm whose MessageDigest provider implementation does not override/allow clone(), then calling generate()/hashBytes().

Common situations: Third-party crypto providers (BouncyCastle in certain modes, hardware/HSM-backed providers) that return non-clonable digest instances.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

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

		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)