oracle/graal · error · FormatVersionException
Unsupported serialized continuation version: %s\nCurrent sup
Error message
Unsupported serialized continuation version: %s\nCurrent supported version: %s
What it means
Thrown as FormatVersionException while deserializing a continuation: the version number encoded in the stream header (bits FORMAT_SHIFT..FORMAT_MASK of the first byte) does not equal ContinuationImpl.FORMAT_VERSION. The library uses this single version number to gate the whole serialized shape (state enum, entry point, frame records), so a mismatch means the bytes cannot be interpreted safely. It exists to fail fast instead of misparsing an incompatible payload.
Source
Thrown at espresso/src/org.graalvm.continuations/src/org/graalvm/continuations/ContinuationImpl.java:657
throw new UnsupportedOperationException("This VM does not support continuations.");
}
ContinuationImpl continuation = new ContinuationImpl();
registerFreshObject.accept(continuation);
continuation.readObjectExternalImpl(in, loader);
return continuation;
}
synchronized void readObjectExternalImpl(ObjectInput in, ClassLoader loader) throws IOException, ClassNotFoundException {
State currentState = lock();
if (currentState == State.RUNNING) {
throw new IllegalContinuationStateException("You cannot serialize a continuation whilst it's running, as this would have unclear semantics. Please suspend first.");
}
try {
// At this point, nothing is initialized
int header = in.readByte();
int version = (header >> FORMAT_SHIFT) & FORMAT_MASK;
if (version != FORMAT_VERSION) {
throw new FormatVersionException(version, FORMAT_VERSION);
}
currentState = (State) in.readObject();
if (currentState == State.RUNNING) {
throw new IllegalContinuationStateException("Illegal serialized continuation is in running state.");
}
entryPoint = (ContinuationEntryPoint) in.readObject();
if (currentState == State.SUSPENDED) {
stackFrameHead = FrameRecordSerializer.forIn(version, in) //
.withLoader(loader == null ? Thread.currentThread().getContextClassLoader() : loader) //
.readRecord();
}
unlock(currentState);
} catch (Throwable e) {
// If any error occurs, leave the continuation as incomplete.
unlock(State.INCOMPLETE);
throw e;View on GitHub (pinned to a66e9ccd1d)
Solutions
- Re-serialize the continuation with the exact same org.graalvm.continuations version that will deserialize it (pin the GraalVM version on both ends).
- If migration is required, resume and re-suspend the continuation under the old runtime, then re-serialize and migrate the new payload.
- Catch FormatVersionException and treat the payload as poison: drop it and rebuild the continuation from its logical starting point instead of retrying.
- Verify the stream was produced by Continuation.serialize and was not truncated/corrupted in transport (check length, checksum) before blaming the version.
Example fix
// before
Continuation c = Continuation.deserialize(bytes, loader);
// after
try {
Continuation c = Continuation.deserialize(bytes, loader);
} catch (FormatVersionException e) {
// payload from an incompatible library version: discard and rebuild
log.warn("Stale continuation payload (version {}), rebuilding", e.getMessage());
return buildFreshContinuation();
} Defensive patterns
Strategy: try-catch
Try / catch
try { Continuation c = Continuation.deserialize(bytes, loader); } catch (FormatVersionException e) { /* payload incompatible: quarantine and rebuild, never retry same bytes */ } Prevention
- Pin producer and consumer of continuation payloads to the identical GraalVM / org.graalvm.continuations version.
- Re-serialize (resume + suspend cycle) persisted continuations as an explicit migration step on every upgrade.
- Store the library version alongside the payload and refuse mismatched payloads before calling deserialize.
When it happens
Trigger: Calling Continuation.deserialize (or ContinuationImpl.readObjectExternalImpl) on bytes produced by a different release of org.graalvm.continuations where FORMAT_VERSION differs; manually crafting or truncating the stream so the header byte decodes to a wrong version.
Common situations: Continuations persisted to disk or sent over the wire between GraalVM builds (e.g. rolling upgrade from an older GraalVM to a newer one); test fixtures recorded with an older library version; mixing continuation classes from two different GraalVM distributions on one classpath.
Related errors
- You can't resume a continuation while it is being serialized
- You cannot serialize a continuation whilst it's running, as
- This VM does not support continuations.
- Unsupported serialized continuation version: %s\nCurrent sup
- Invalid replay string table index
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/c03266560ed788ef.
Report an issue: GitHub.