oracle/graal · error · IllegalContinuationStateException
This continuation has already completed successfully.
Error message
This continuation has already completed successfully.
What it means
IllegalContinuationStateException raised by resume() when the continuation has already run to completion (state COMPLETED). A finished continuation holds no suspended frames and cannot be restarted; a new Continuation must be created instead.
Source
Thrown at espresso/src/org.graalvm.continuations/src/org/graalvm/continuations/ContinuationImpl.java:378
} finally {
clearExclusiveOwner();
}
} else if (updateState(State.SUSPENDED, State.RUNNING)) {
setExclusiveOwner();
try {
// We are ready to resume, make sure the VM has the most up-to-date frames
ensureDematerialized();
assert stackFrameHead == null;
return resume0();
} finally {
clearExclusiveOwner();
}
} else {
// illegal state for resume: neither suspended nor new
switch (state) {
case RUNNING -> throw new IllegalContinuationStateException("You can't resume an already executing continuation.");
case COMPLETED ->
throw new IllegalContinuationStateException("This continuation has already completed successfully.");
case FAILED -> throw new IllegalContinuationStateException("This continuation has failed and must be discarded.");
case LOCKED -> throw new IllegalContinuationStateException("You can't resume a continuation while it is being serialized or deserialized.");
// this is racy so ensure we have a general error message in those case
default -> throw new IllegalContinuationStateException("Only new or suspended continuation can be resumed");
}
}
}
@Override
public synchronized StackTraceElement[] getRecordedFrames() {
State currentState = lock();
try {
ensureDematerialized();
return getRecordedFrames0();
} finally {
unlock(currentState);
}
}View on GitHub (pinned to a66e9ccd1d)
Solutions
- Honour the boolean result of resume(): true means finished; stop resuming.
- Check isCompleted() before calling resume().
- Create a fresh Continuation for each new run of the workload.
- Model repeated work as suspend/resume inside one lifetime, not as repeated resumes after completion.
Example fix
// before
while (true) {
continuation.resume(); // keeps throwing once completed
}
// after
while (!continuation.resume()) {
// suspended again; do scheduling work
}
// resume() returned true: completed, do not resume again Defensive patterns
Strategy: validation
Validate before calling
if (continuation.isCompleted()) {
// finished; create a new Continuation if the work must run again
} Prevention
- Use the boolean result of resume() to terminate resume loops.
- Check isCompleted() before retry loops.
- Create a new continuation per run for repeatable jobs.
When it happens
Trigger: Calling resume() after resume() previously returned true (completion); looping 'while (!result) resume()' and ignoring the completion result; retry logic that blindly resumes after the entry point finished.
Common situations: Task-runner loops that resume until done but miss the terminal return value; re-running a one-shot job implemented as a continuation.
Related errors
- This continuation has failed and must be discarded.
- Suspend capabilities can only be used inside a running conti
- You can't resume an already executing continuation.
- You can't resume a continuation while it is being serialized
- Only new or suspended continuation can be resumed
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/805aa184a2b6a66f.
Report an issue: GitHub.