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

  1. 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.
  2. Set Thread.currentThread().setContextClassLoader(appLoader) before deserialize if you rely on the default.
  3. Keep class versions identical between the runtime that suspended and the one that resumes (no renames/removals of methods that appear on the stack).
  4. 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

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


AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14). Data as JSON: /api/errors/6f191c09158e7b12. Report an issue: GitHub.