{"record":{"id":"310cf5de5461e44e","repo":"quarkusio/quarkus","slug":"attempting-a-blocking-read-on-io-thread","errorCode":null,"errorMessage":"Attempting a blocking read on io thread","messagePattern":"Attempting a blocking read on io thread","errorType":"exception","errorClass":"BlockingOperationNotAllowedException","httpStatus":null,"severity":"error","filePath":"extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxInputStream.java","lineNumber":245,"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 BlockingOperationNotAllowedException(\"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":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxInputStream.java#L227-L263","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Annotate the endpoint or filter @Blocking, or use @RunOnVirtualThread, so the handler runs on a worker thread.","Read the request body using the reactive API (e.g. route body handler / Multi<Buffer>) instead of the blocking InputStream.","In filters/interceptors, dispatch to a worker executor before consuming the body.","Avoid manual InputStream reads inside Vert.x handlers; let the framework buffer the body first."],"exampleFix":"// before\n@POST\npublic String upload() throws IOException {  // runs on event-loop\n    return new String(request.getInputStream().readAllBytes());\n}\n// after\n@POST\n@RunOnVirtualThread   // or @Blocking\npublic String upload() throws IOException {\n    return new String(request.getInputStream().readAllBytes());\n}","handlingStrategy":"try-catch","validationCode":"if (io.vertx.core.Context.isOnEventLoopThread()) {\n    throw new IllegalStateException(\"Body must be read on a worker thread: use @Blocking / @RunOnVirtualThread or the reactive body API\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    in.read(buf);\n} catch (BlockingOperationNotAllowedException e) {\n    // re-dispatch to worker executor and retry the read there\n    workerExecutor.executeBlocking(() -> readBody(in));\n}","preventionTips":["Annotate body-consuming endpoints @Blocking or @RunOnVirtualThread","Prefer reactive body handlers (Multi<Buffer>) on event-loop code","Never read InputStreams inside Vert.x handlers"],"tags":["blocking","event-loop","vertx","reactive","quarkus"],"backgroundTag":"blocking-operation-not-allowed-on-io-thread","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"}