quarkusio/quarkus · error · BlockingOperationNotAllowedException

Attempting a blocking read on io thread

Error message

Attempting a blocking read on io thread

What it means

Blocking reads on the request InputStream are forbidden on the Vert.x event-loop (IO) thread. VertxInputStream.readBlocking checks Context.isOnEventLoopThread() and throws BlockingOperationNotAllowedException("Attempting a blocking read on io thread") to prevent freezing all request processing.

Source

Thrown at extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxInputStream.java:245

        }

        protected ByteBuf readBlocking() throws IOException {
            long expire = System.currentTimeMillis() + timeout;
            synchronized (request.connection()) {
                while (input1 == null && !eof && readException == null) {
                    long rem = expire - System.currentTimeMillis();
                    if (rem <= 0) {
                        //everything is broken, if read has timed out we can assume that the underling connection
                        //is wrecked, so just close it
                        request.connection().close();
                        IOException throwable = new IOException("Read timed out");
                        readException = throwable;
                        throw throwable;
                    }

                    try {
                        if (Context.isOnEventLoopThread()) {
                            throw new BlockingOperationNotAllowedException("Attempting a blocking read on io thread");
                        }
                        waiting = true;
                        request.connection().wait(rem);
                    } catch (InterruptedException e) {
                        throw new InterruptedIOException(e.getMessage());
                    } finally {
                        waiting = false;
                    }
                }
                if (readException != null) {
                    throw new IOException(readException);
                }
                Buffer ret = input1;
                input1 = null;
                if (inputOverflow != null) {
                    input1 = inputOverflow.poll();
                    if (input1 == null) {
                        request.fetch(1);

View on GitHub (pinned to e1c734241f)

Solutions

  1. Annotate the endpoint or filter @Blocking, or use @RunOnVirtualThread, so the handler runs on a worker thread.
  2. Read the request body using the reactive API (e.g. route body handler / Multi<Buffer>) instead of the blocking InputStream.
  3. In filters/interceptors, dispatch to a worker executor before consuming the body.
  4. Avoid manual InputStream reads inside Vert.x handlers; let the framework buffer the body first.

Example fix

// before
@POST
public String upload() throws IOException {  // runs on event-loop
    return new String(request.getInputStream().readAllBytes());
}
// after
@POST
@RunOnVirtualThread   // or @Blocking
public String upload() throws IOException {
    return new String(request.getInputStream().readAllBytes());
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (io.vertx.core.Context.isOnEventLoopThread()) {
    throw new IllegalStateException("Body must be read on a worker thread: use @Blocking / @RunOnVirtualThread or the reactive body API");
}

Try / catch

try {
    in.read(buf);
} catch (BlockingOperationNotAllowedException e) {
    // re-dispatch to worker executor and retry the read there
    workerExecutor.executeBlocking(() -> readBody(in));
}

Prevention

When it happens

Trigger: Calling in.read() (which waits via request.connection().wait) on the request body from code running on an event-loop thread — e.g. inside a non-blocking route handler, a Vert.x handler, or a filter not marked @Blocking.

Common situations: RESTEasy Reactive / Vert.x route handlers that consume the raw InputStream directly; Quarkus Security or filter code reading the body on the IO thread; migrating servlet-style blocking code into reactive endpoints without @Blocking/@RunOnVirtualThread.

Related errors


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