quarkusio/quarkus · error · IllegalStateException
VertxContextSupport#subscribeAndAwait() must not be called o
Error message
VertxContextSupport#subscribeAndAwait() must not be called on an event loop!
What it means
VertxContextSupport.subscribeAndAwait() blocks the current thread waiting for a CompletionStage to complete, which is illegal on a Vert.x event loop thread. VertxContextSupport.getContext detects this combination (non-blocking call attempted on an event loop thread) and throws IllegalStateException to avoid deadlocking the event loop.
Source
Thrown at extensions/vertx/runtime/src/main/java/io/quarkus/vertx/VertxContextSupport.java:138
return callable.call();
} finally {
if (terminate) {
requestContext.terminate();
}
}
}, false).toCompletionStage();
});
}
private static Context getContext(boolean blocking) {
Context context = Vertx.currentContext();
if (context == null) {
Vertx vertx = VertxCoreRecorder.getVertx().get();
context = VertxContext.getOrCreateDuplicatedContext(vertx);
} else {
// Executed on a vertx thread...
if (!blocking && Context.isOnEventLoopThread()) {
throw new IllegalStateException("VertxContextSupport#subscribeAndAwait() must not be called on an event loop!");
}
context = VertxContext.getOrCreateDuplicatedContext(context);
}
return context;
}
}
View on GitHub (pinned to e1c734241f)
Solutions
- Move the call to a worker thread: annotate the method @Blocking or offload via Uni.runSubscriptionOn(Executors.newSingleThreadExecutor())
- Use non-blocking composition (chain the Uni/CompletionStage with map/chain) instead of awaiting
- If running under RESTEasy Reactive, make the endpoint return Uni<?> instead of blocking
Example fix
// before
String result = vertxContextSupport.subscribeAndAwait(uni); // on event loop
// after
@Blocking
String handler() { return vertxContextSupport.subscribeAndAwait(uni); }
// or: return uni.await().atMost(Duration.ofSeconds(5)) inside a @Blocking method; Defensive patterns
Strategy: validation
Validate before calling
import io.vertx.core.Context;
if (Context.isOnEventLoopThread()) {
throw new IllegalStateException("Move subscribeAndAwait to a worker thread or use non-blocking composition");
} Prevention
- Never call .await()/blocking getters inside event-loop handlers; annotate with @Blocking instead
- Return Uni/CompletionStage from reactive endpoints instead of blocking
- Guard shared utility methods with Context.isOnEventLoopThread() checks
When it happens
Trigger: Calling code that ultimately reaches VertxContextSupport.subscribeAndAwait() (e.g. blocking bridging of a Uni/CompletionStage) while the current thread is a Vert.x event loop thread; getContext throws when !blocking && Context.isOnEventLoopThread().
Common situations: Calling .await() or .subscribeAsCompletionStage().get() style helpers inside an event-loop handler, a synchronous REST resource method running on the event loop, or a sync startup/observer method that blocks on a Uni.
Related errors
- You have attempted to perform a blocking operation on a IO t
- You have attempted to inject AuthzClient on a IO thread. Thi
- Attempting a blocking write on io thread
- Attempting a blocking read on io thread
- Attempting a blocking read on io thread
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/69940abe38bcf131.
Report an issue: GitHub.