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

  1. Move the call to a worker thread: annotate the method @Blocking or offload via Uni.runSubscriptionOn(Executors.newSingleThreadExecutor())
  2. Use non-blocking composition (chain the Uni/CompletionStage with map/chain) instead of awaiting
  3. 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

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


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/69940abe38bcf131. Report an issue: GitHub.