{"record":{"id":"bffc2309a2d04ece","repo":"quarkusio/quarkus","slug":"attempting-a-blocking-read-on-io-thread-bffc23","errorCode":null,"errorMessage":"Attempting a blocking read on io thread","messagePattern":"Attempting a blocking read on io thread","errorType":"exception","errorClass":"BlockingNotAllowedException","httpStatus":null,"severity":"error","filePath":"independent-projects/resteasy-reactive/server/vertx/src/main/java/org/jboss/resteasy/reactive/server/vertx/VertxInputStream.java","lineNumber":247,"sourceCode":"        }\n\n        protected ByteBuf readBlocking() throws IOException {\n            long expire = System.currentTimeMillis() + timeout;\n            synchronized (request.connection()) {\n                while (input1 == null && !eof && readException == null) {\n                    long rem = expire - System.currentTimeMillis();\n                    if (rem <= 0) {\n                        //everything is broken, if read has timed out we can assume that the underling connection\n                        //is wrecked, so just close it\n                        request.connection().close();\n                        IOException throwable = new IOException(\"Read timed out\");\n                        readException = throwable;\n                        throw throwable;\n                    }\n\n                    try {\n                        if (Context.isOnEventLoopThread()) {\n                            throw new BlockingNotAllowedException(\"Attempting a blocking read on io thread\");\n                        }\n                        waiting = true;\n                        request.connection().wait(rem);\n                    } catch (InterruptedException e) {\n                        throw new InterruptedIOException(e.getMessage());\n                    } finally {\n                        waiting = false;\n                    }\n                }\n                if (readException != null) {\n                    throw new IOException(readException);\n                }\n                Buffer ret = input1;\n                input1 = null;\n                if (inputOverflow != null) {\n                    input1 = inputOverflow.poll();\n                    if (input1 == null) {\n                        request.fetch(1);","sourceCodeStart":229,"sourceCodeEnd":265,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/resteasy-reactive/server/vertx/src/main/java/org/jboss/resteasy/reactive/server/vertx/VertxInputStream.java#L229-L265","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n@GET @Path(\"/upload\")\npublic String read(InputStream is) { is.read(); } // runs on event loop -> exception\n// after\n@GET @Path(\"/upload\")\n@Blocking\npublic String read(InputStream is) { is.read(); } // worker thread, blocking allowed","handlingStrategy":"validation","validationCode":"if (io.vertx.core.Context.isOnEventLoopThread()) {\n    throw new IllegalStateException(\"Move body reads to a worker/@Blocking thread\");\n}\nstream.read(buf);","typeGuard":null,"tryCatchPattern":"try {\n    stream.read(buf);\n} catch (org.jboss.resteasy.reactive.common.core.BlockingNotAllowedException e) {\n    // reschedule read on a worker executor\n}","preventionTips":["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."],"tags":["event-loop","blocking","reactive","concurrency"],"backgroundTag":"blocking-on-event-loop","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}