quarkusio/quarkus · error
A task is already pending
Error message
A task is already pending
What it means
evaluateInRenderThread() allows only one in-flight evaluation per RemoteThread. It throws IllegalStateException('A task is already pending') when a second evaluation is scheduled before the previous one's pendingTask is consumed by the render thread.
Source
Thrown at independent-projects/qute/debug/src/main/java/io/quarkus/qute/debug/agent/RemoteThread.java:367
* compatibility with request-bound state.
* </p>
*
* @param action the task to execute within the render thread context.
* It should return a {@link CompletableFuture} representing the computation result.
* @return a {@link CompletableFuture} containing the result of the executed task
* @throws IllegalStateException if the thread is not currently suspended or if another
* evaluation task is already pending
*/
public CompletableFuture<Object> evaluateInRenderThread(Callable<CompletableFuture<Object>> action) {
synchronized (lock) {
// Ensure the render thread is suspended before executing any task
if (this.state != DebuggerState.SUSPENDED) {
throw new IllegalStateException("Thread not suspended");
}
// Prevent concurrent evaluation tasks from overlapping
if (pendingTask != null) {
throw new IllegalStateException("A task is already pending");
}
// Schedule the evaluation task to be executed by the render thread
pendingTask = action;
taskResult = null;
// Wake up the suspended render thread so it can pick up and execute the task
lock.notifyAll();
// Wait for the render thread to process and complete the pending task
boolean intr = false;
try {
while (pendingTask != null) {
try {
lock.wait();
} catch (InterruptedException e) {
intr = true;
}View on GitHub (pinned to e1c734241f)
Solutions
- Serialize evaluations: wait for the previous evaluateInRenderThread() CompletableFuture to complete before submitting another.
- Catch IllegalStateException and retry after the pending task finishes.
- Queue evaluations per thread instead of issuing them concurrently.
- Investigate why the previous evaluation never completed (a blocking/long-running expression can wedge pendingTask).
Example fix
// before thread.evaluateInRenderThread(a1); thread.evaluateInRenderThread(a2); // throws // after thread.evaluateInRenderThread(a1).thenRun(() -> thread.evaluateInRenderThread(a2));
Defensive patterns
Strategy: validation
Validate before calling
synchronized (thread) {
if (pendingEvaluationInFlight) throw new IllegalStateException("serialize evaluations");
pendingEvaluationInFlight = true;
}
thread.evaluateInRenderThread(action).whenComplete((r, e) -> pendingEvaluationInFlight = false); Try / catch
try {
return thread.evaluateInRenderThread(action).get();
} catch (IllegalStateException e) {
if ("A task is already pending".equals(e.getMessage())) {
// queue or retry after the current evaluation completes
}
throw e;
} Prevention
- Serialize evaluations per thread (no concurrent evaluate calls)
- Queue watch/hover evaluations instead of firing in parallel
- Investigate evaluations that never complete — they wedge the pending slot
When it happens
Trigger: Issuing two overlapping evaluate requests on the same suspended render thread — e.g. a DAP client sending multiple evaluateRequests (watch expressions, hover, repl) before the first completes.
Common situations: IDE watch panels firing several evaluations at once on breakpoint hit; batch variable evaluation scripts; a slow evaluation (blocking expression) causing the UI to re-issue requests.
Related errors
- Thread not suspended
- InvalidRequest
- Tests already in progress
- The application is stopping
- Unable to render config roots for top level prefix: ${topLev
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/cb7842157f9d8ea5.
Report an issue: GitHub.