{"record":{"id":"d4137eadbf299dea","repo":"oracle/graal","slug":"suspend-capabilities-can-only-be-used-inside-a-con","errorCode":null,"errorMessage":"Suspend capabilities can only be used inside a continuation.","messagePattern":"Suspend capabilities can only be used inside a continuation\\.","errorType":"exception","errorClass":"IllegalContinuationStateException","httpStatus":null,"severity":"error","filePath":"espresso/src/org.graalvm.continuations/src/org/graalvm/continuations/ContinuationImpl.java","lineNumber":473,"sourceCode":"            sb.append(\"    Primitives: \");\n            for (int j = 1; j < record.primitives.length; j++) {\n                sb.append(record.primitives[j]);\n                if (j < record.pointers.length - 1) {\n                    sb.append(\", \");\n                }\n            }\n            sb.append(\"\\n\");\n        }\n        return sb.toString();\n    }\n\n    /**\n     * Called from {@link SuspendCapability#suspend()}. Suspends this continuation. If successful,\n     * execution resumes back at {@link #resume()}.\n     */\n    void trySuspend() {\n        if (exclusiveOwner != Thread.currentThread()) {\n            throw new IllegalContinuationStateException(\"Suspend capabilities can only be used inside a continuation.\");\n        }\n        if (!updateState(State.RUNNING, State.SUSPENDED)) {\n            throw new IllegalContinuationStateException(\"Suspend capabilities can only be used inside a running continuation.\");\n        }\n        try {\n            suspend();\n        } catch (IllegalContinuationStateException e) {\n            if (!updateState(State.SUSPENDED, State.RUNNING)) {\n                // force failed state and maybe assert\n                State badState = forceState(State.RUNNING);\n                if (ASSERTIONS_ENABLED) {\n                    AssertionError assertionError = new AssertionError(badState.toString());\n                    assertionError.addSuppressed(e);\n                    throw assertionError;\n                }\n            }\n            throw e;\n        }","sourceCodeStart":455,"sourceCodeEnd":491,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/espresso/src/org.graalvm.continuations/src/org/graalvm/continuations/ContinuationImpl.java#L455-L491","documentation":"IllegalContinuationStateException from ContinuationImpl.trySuspend (backing SuspendCapability.suspend()) when the calling thread is not the continuation's exclusive owner. Suspend capabilities are only usable from code physically executing inside the continuation on its resume thread; calling suspend() from an unrelated thread is rejected.","triggerScenarios":"Invoking capability.suspend() from outside the continuation body (e.g. application main thread, another worker); storing the SuspendCapability in a shared field and calling it from a scheduler thread; unit tests calling suspend() directly on a capability handed out earlier.","commonSituations":"Passing the capability to async framework callbacks (CompletableFuture completions on foreign thread pools) that call suspend() when they fire; sharing the capability across an executor.","solutions":["Only call SuspendCapability.suspend() from within the continuation entry point, on the thread that resumed it.","Do not leak the capability to other threads; treat it as thread-confined.","For cross-thread signaling, use a blocking queue/latch inside the continuation so the continuation's own thread performs the suspend.","Ensure async callbacks re-enter the continuation thread before suspending."],"exampleFix":"// before\nCompletableFuture.supplyAsync(work, foreignPool).thenRun(() -> capability.suspend()); // wrong thread\n\n// after\n// inside the continuation entry point, on its own thread:\nSomeResult r = blockingCall(); // blocks this thread instead\ncapability.suspend(); // called by the continuation's own thread","handlingStrategy":"validation","validationCode":"// inside the continuation entry point only:\nif (Thread.currentThread() != resumeThread) {\n    throw new IllegalStateException(\"suspend must run on the continuation thread\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat SuspendCapability as thread-confined; never share it.","Use blocking primitives inside the continuation instead of foreign-thread callbacks.","Ensure async callbacks hop back to the continuation thread before suspending."],"tags":["continuations","illegal-state","thread-confinement","concurrency","graalvm","truffle"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}