oracle/graal · error · IOException
Failed to deserialize frame for %s.%s().
Error message
Failed to deserialize frame for %s.%s().
What it means
The wrapper IOException ('Failed to deserialize frame for %s.%s().') that readFrame throws after catching any IOException or ClassNotFoundException raised while rebuilding a single stack frame. The real failure is attached as the cause: typically a ClassNotFoundException when the frame's declaring class is not loadable by the classloader supplied to withLoader (defaults to the thread context classloader), or one of the embedded frame-format errors ('Missing this', 'Unexpected kind').
Source
Thrown at espresso/src/org.graalvm.continuations/src/org/graalvm/continuations/FrameRecordSerializer.java:270
try {
Object[] pointers = (Object[]) in.readObject();
// Try to obtain type information for possible error reporting.
// Slot zero is always primitive (bci), so this is in slot 1.
if (holder == null) {
possibleThis = pointers.length > THIS_POS ? pointers[THIS_POS] : null;
if (possibleThis == null) {
throw new IOException("Missing this in serialized frame.");
}
holder = possibleThis.getClass().getName();
}
long[] primitives = (long[]) in.readObject();
Method method = readMethodNameAndTypes(loader, possibleThis, methodName, holder);
int bci = in.readInt();
return new ContinuationImpl.FrameRecord(pointers, primitives, method, bci);
} catch (IOException | ClassNotFoundException e) {
throw new IOException("Failed to deserialize frame for %s.%s().".formatted((holder == null ? "?" : holder), methodName), e);
}
}
private String readMethodName() throws IOException {
return readString();
}
private String readHolder() throws IOException {
assert in != null;
if (in.readBoolean()) {
return null;
} else {
return readString();
}
}
private Method readMethodNameAndTypes(ClassLoader classLoader, Object possibleThis, String name, String holder)
throws IOException, ClassNotFoundException, NoSuchMethodException {View on GitHub (pinned to a66e9ccd1d)
Solutions
- Read the cause: if ClassNotFoundException, ensure the frame's class (holder from the message) is on the deserializing classloader — pass an explicit loader covering all classes on the continuation's stack, not the implicit context classloader.
- Set Thread.currentThread().setContextClassLoader(appLoader) before deserialize if you rely on the default.
- Keep class versions identical between the runtime that suspended and the one that resumes (no renames/removals of methods that appear on the stack).
- Catch IOException from deserialize and quarantine the payload with the frame coordinates from the message for diagnosis.
Example fix
// before Continuation c = Continuation.deserialize(bytes, null); // falls back to ctx loader, misses app classes // after Continuation c = Continuation.deserialize(bytes, appClassLoader); // loader that sees every frame's class
Defensive patterns
Strategy: validation
Validate before calling
// before deserialize, confirm every class named in the payload is loadable
for (String cn : payloadClassNames(bytes)) {
Class.forName(cn, false, appClassLoader); // throws ClassNotFoundException early with a clear message
} Try / catch
try { Continuation.deserialize(bytes, appClassLoader); } catch (IOException e) { if (e.getCause() instanceof ClassNotFoundException cnf) { /* class missing on loader: fix classpath/layer */ } } Prevention
- Always pass an explicit ClassLoader that sees all classes on the continuation stack; do not rely on the thread context loader.
- Set the context classloader appropriately if you must rely on the default.
- Treat methods on suspendable stacks as a serialization contract: no renames/signature changes across deployments.
When it happens
Trigger: Deserializing a continuation whose stack includes a class not present on the loader passed to Continuation.deserialize/readObjectExternalImpl; the app server or deserializing thread has a context classloader that cannot see the application's classes.
Common situations: Resuming a continuation on a node where a newer class layout or renamed class exists; deserializing from a background thread whose context classloader is the system loader instead of the app loader; OSGi/modular deployments where the frame's classes live in a bundle not wired to the reader.
Related errors
- Missing this in serialized frame.
- Setting ihashcode of an object whose ihashcode is already in
- Erroneous deserialization of SuspendCapability.\nread object
- You can't resume a continuation while it is being serialized
- You cannot serialize a continuation whilst it's running, as
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/6f191c09158e7b12.
Report an issue: GitHub.