quarkusio/quarkus · error · BlockingNotAllowedException
Attempting a blocking read on io thread
Error message
Attempting a blocking read on io thread
What it means
readBlocking() throws BlockingNotAllowedException('Attempting a blocking read on io thread') when the request body is not yet buffered and the current thread is a Vert.x event-loop thread. Blocking waits on the event loop would stall all other requests on that thread, so the framework refuses it.
Source
Thrown at independent-projects/resteasy-reactive/server/vertx/src/main/java/org/jboss/resteasy/reactive/server/vertx/VertxInputStream.java:247
}
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 BlockingNotAllowedException("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
- Annotate the endpoint/handler with @Blocking (Jakarta REST) or move the read to a worker thread/executUserBlocking code.
- Consume the request body reactively instead (RoutingContext.body() / multipart data) so no blocking wait is needed.
- Ensure the body is fully buffered before switching to event-loop code that reads the stream.
Example fix
// before
@GET @Path("/upload")
public String read(InputStream is) { is.read(); } // runs on event loop -> exception
// after
@GET @Path("/upload")
@Blocking
public String read(InputStream is) { is.read(); } // worker thread, blocking allowed Defensive patterns
Strategy: validation
Validate before calling
if (io.vertx.core.Context.isOnEventLoopThread()) {
throw new IllegalStateException("Move body reads to a worker/@Blocking thread");
}
stream.read(buf); Try / catch
try {
stream.read(buf);
} catch (org.jboss.resteasy.reactive.common.core.BlockingNotAllowedException e) {
// reschedule read on a worker executor
} Prevention
- Annotate endpoints that read the body with @Blocking.
- Never call blocking InputStream reads in reactive handlers/observers on the event loop.
- Prefer reactive body access (RoutingContext.body()) in non-blocking code.
When it happens
Trigger: Reading the request InputStream (directly or via blocking APIs like a Jakarta REST blocking endpoint that actually runs on the event loop) when the body hasn't fully arrived and Context.isOnEventLoopThread() is true.
Common situations: Calling blocking body reads inside non-blocking REST methods, Vert.x route handlers, or observers running on the event loop; misconfigured @Blocking annotation; using InputStream in a reactive handler.
Related errors
- Blocking gRPC client call made from the event loop. If the c
- You have attempted to perform a blocking operation on a IO t
- @Transactional cannot start a JTA transaction within a react
- 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/bffc2309a2d04ece.
Report an issue: GitHub.