{"record":{"id":"a530710d97f8270b","repo":"oracle/graal","slug":"only-new-or-suspended-continuation-can-be-resumed","errorCode":null,"errorMessage":"Only new or suspended continuation can be resumed","messagePattern":"Only new or suspended continuation can be resumed","errorType":"exception","errorClass":"IllegalContinuationStateException","httpStatus":null,"severity":"error","filePath":"espresso/src/org.graalvm.continuations/src/org/graalvm/continuations/ContinuationImpl.java","lineNumber":382,"sourceCode":"            setExclusiveOwner();\n            try {\n                // We are ready to resume, make sure the VM has the most up-to-date frames\n                ensureDematerialized();\n                assert stackFrameHead == null;\n                return resume0();\n            } finally {\n                clearExclusiveOwner();\n            }\n        } else {\n            // illegal state for resume: neither suspended nor new\n            switch (state) {\n                case RUNNING -> throw new IllegalContinuationStateException(\"You can't resume an already executing continuation.\");\n                case COMPLETED ->\n                    throw new IllegalContinuationStateException(\"This continuation has already completed successfully.\");\n                case FAILED -> throw new IllegalContinuationStateException(\"This continuation has failed and must be discarded.\");\n                case LOCKED -> throw new IllegalContinuationStateException(\"You can't resume a continuation while it is being serialized or deserialized.\");\n                // this is racy so ensure we have a general error message in those case\n                default -> throw new IllegalContinuationStateException(\"Only new or suspended continuation can be resumed\");\n            }\n        }\n    }\n\n    @Override\n    public synchronized StackTraceElement[] getRecordedFrames() {\n        State currentState = lock();\n        try {\n            ensureDematerialized();\n            return getRecordedFrames0();\n        } finally {\n            unlock(currentState);\n        }\n    }\n\n    @Override\n    @SuppressWarnings(\"deprecation\")\n    public String toDebugString() {","sourceCodeStart":364,"sourceCodeEnd":400,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/espresso/src/org.graalvm.continuations/src/org/graalvm/continuations/ContinuationImpl.java#L364-L400","documentation":"Catch-all IllegalContinuationStateException from resume() when the observed state is none of RUNNING, COMPLETED, FAILED, or LOCKED. Because the state field is read racily, the exact state can change between the CAS attempts and the report; this generic message covers transient states such as NEW-with-concurrent-transition or mid-serialization INCOMPLETE.","triggerScenarios":"Concurrent resume() calls from multiple threads on the same fresh continuation where the loser of the first CAS reads a stale state; resume() racing with serialization state transitions (INCOMPLETE/LOCKED).","commonSituations":"Multi-threaded schedulers sharing one continuation without external synchronization; tests hammering resume from several threads to probe races.","solutions":["Externalize a lock so only one thread performs resume() at a time; the internal state machine is not a substitute for caller synchronization.","Re-check getState() after the exception and decide based on the fresh value.","Treat this exception as a concurrency bug in caller code: audit all resume/suspend/serialize call sites for races.","Single-thread continuation ownership (actor/pinned worker) removes the class of problem."],"exampleFix":"// before\nexecutors.forEach(ex -> ex.submit(() -> continuation.resume())); // racing resumes\n\n// after\n// single owner:\nworkerThread.submit(() -> {\n    while (!continuation.resume()) { /* schedule */ }\n});","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    continuation.resume();\n} catch (IllegalContinuationStateException e) {\n    switch (continuation.getState()) {\n        case SUSPENDED, NEW -> continuation.resume(); // safe to retry once\n        default -> throw e; // real lifecycle problem\n    }\n}","preventionTips":["Serialize all resume() calls through one thread or lock.","Treat this message as a caller-side race signal; audit concurrency.","Pin continuation ownership to one worker (actor style)."],"tags":["continuations","illegal-state","concurrency","race-condition","graalvm","truffle"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}