{"record":{"id":"11428272901c2130","repo":"oracle/graal","slug":"failed-to-dematerialize-continuation-frames","errorCode":null,"errorMessage":"Failed to dematerialize continuation frames.","messagePattern":"Failed to dematerialize continuation frames\\.","errorType":"exception","errorClass":"IllegalMaterializedRecordException","httpStatus":null,"severity":"error","filePath":"espresso/src/org.graalvm.continuations/src/org/graalvm/continuations/ContinuationImpl.java","lineNumber":791,"sourceCode":"    private void ensureDematerialized() {\n        if (stackFrameHead == null) {\n            // No frame to dematerialize\n            return;\n        }\n        synchronized (this) {\n            State previousState = lock();\n            if (previousState == State.RUNNING) {\n                dematerialize0();\n            } else {\n                try {\n                    dematerialize0();\n                } finally {\n                    unlock(previousState);\n                }\n            }\n        }\n        if (stackFrameHead != null) {\n            throw new IllegalMaterializedRecordException(\"Failed to dematerialize continuation frames.\");\n        }\n    }\n\n    @Override\n    public String toString() {\n        String status;\n        switch (getState()) {\n            case NEW: // fallthrough\n            case SUSPENDED:\n                status = \"Resumable\";\n                break;\n            case RUNNING:\n                status = \"Running\";\n                break;\n            case COMPLETED: // fallthrough\n            case FAILED:\n                status = \"Completed\";\n                break;","sourceCodeStart":773,"sourceCodeEnd":809,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/espresso/src/org.graalvm.continuations/src/org/graalvm/continuations/ContinuationImpl.java#L773-L809","documentation":"Thrown as IllegalMaterializedRecordException by ContinuationImpl's dematerialize path: after dematerialize0() ran (with the continuation locked), stackFrameHead is still non-null. stackFrameHead anchors the linked list of materialized FrameRecords, so a non-null head after dematerialization means frames were left behind — an internal invariant violation of the continuation bookkeeping rather than a user input error.","triggerScenarios":"dematerialize() or the internal record-pathway (e.g. during suspend/serialization support) completing while FrameRecords remain reachable from stackFrameHead; typically caused by a bug in the frame-walking/record logic or by concurrent manipulation of the continuation from multiple threads.","commonSituations":"Two threads resuming/suspending/dematerializing the same Continuation instance concurrently; hitting a bug in a specific GraalVM build's continuation instrumentation; a partially-updated workspace mixing old and new espresso/continuation classes.","solutions":["Audit for concurrent access to the same Continuation object and serialize all start/suspend/dematerialize calls through one owner thread or an external lock.","Reproduce on a clean, single-suite build (mx build) — mixed stale classes can break FrameRecord invariants.","If it reproduces deterministically on the latest GraalVM with single-threaded usage, file a GraalVM issue with the continuation code and stack trace.","Do not retry dematerialize() on the same instance — the FrameRecord chain is already in an unknown state; create a new continuation instead."],"exampleFix":"// before\nnew Thread(() -> cont.start(entry)).start();\nnew Thread(() -> cont.dematerialize()).start(); // races on FrameRecords\n\n// after\n// single owner thread drives every lifecycle transition\nexecutor.execute(() -> {\n    cont.start(entry);\n    cont.suspend();\n    cont.dematerialize();\n});","handlingStrategy":"validation","validationCode":"// before any lifecycle call, assert single ownership\nif (!contOwnerThread.compareAndSet(null, Thread.currentThread())) {\n    throw new IllegalStateException(\"Continuation already owned by \" + contOwnerThread.get());\n}","typeGuard":null,"tryCatchPattern":"try { cont.dematerialize(); } catch (IllegalMaterializedRecordException e) { /* internal invariant broken: abandon this instance, report bug upstream */ }","preventionTips":["Drive every start/suspend/dematerialize transition of a Continuation from one owner thread.","Never retry dematerialize on the same instance after this exception.","Reproduce on a clean single-version build before reporting; mixed builds break frame-record invariants."],"tags":["continuations","internal-invariant","concurrency","graalvm"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}