{"record":{"id":"c1cd16cb468eaf5a","repo":"quarkusio/quarkus","slug":"you-have-attempted-to-perform-a-blocking-operation","errorCode":null,"errorMessage":"You have attempted to perform a blocking operation on a IO thread. This is not allowed, as blocking the IO thread will cause major performance issues with your application. If you want to perform blocking EntityManager operations make sure you are doing it from a worker thread.","messagePattern":"You have attempted to perform a blocking operation on a IO thread\\. This is not allowed, as blocking the IO thread will cause major performance issues with your application\\. If you want to perform blocking EntityManager operations make sure you are doing it from a worker thread\\.","errorType":"exception","errorClass":"BlockingOperationNotAllowedException","httpStatus":null,"severity":"error","filePath":"extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/session/TransactionScopedSession.java","lineNumber":141,"sourceCode":"                        false, false);\n            } else {\n                throw new ContextNotActiveException(\n                        \"Cannot use the EntityManager/Session because neither a transaction nor a CDI request context is active.\"\n                                + \" Consider adding @Transactional to your method to automatically activate a transaction,\"\n                                + \" or @ActivateRequestContext if you have valid reasons not to use transactions.\");\n            }\n        } else {\n            throw new ContextNotActiveException(\n                    \"Cannot use the EntityManager/Session because no transaction is active.\"\n                            + \" Consider adding @Transactional to your method to automatically activate a transaction,\"\n                            + \" or set '\" + HibernateOrmRuntimeConfig.extensionPropertyKey(\"request-scoped.enabled\")\n                            + \"' to 'true' if you have valid reasons not to use transactions.\");\n        }\n    }\n\n    private void checkBlocking() {\n        if (!BlockingOperationControl.isBlockingAllowed()) {\n            throw new BlockingOperationNotAllowedException(\n                    \"You have attempted to perform a blocking operation on a IO thread. This is not allowed, as blocking the IO thread will cause major performance issues with your application. If you want to perform blocking EntityManager operations make sure you are doing it from a worker thread.\");\n        }\n    }\n\n    private boolean isInTransaction() {\n        try {\n            switch (transactionManager.getStatus()) {\n                case Status.STATUS_ACTIVE:\n                case Status.STATUS_COMMITTING:\n                case Status.STATUS_MARKED_ROLLBACK:\n                case Status.STATUS_PREPARED:\n                case Status.STATUS_PREPARING:\n                    return true;\n                default:\n                    return false;\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(e);","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/session/TransactionScopedSession.java#L123-L159","documentation":"checkBlocking() in TransactionScopedSession guards every EntityManager operation with BlockingOperationControl. Hibernate's EntityManager does JDBC (blocking) I/O, so calling it from a Vert.x event-loop / IO thread would stall the event loop; Quarkus therefore throws BlockingOperationNotAllowedException telling you to run the operation on a worker thread.","triggerScenarios":"Calling persist, merge, remove, find, findMultiple, getReference (or any other method on the injected EntityManager) while BlockingOperationControl.isBlockingAllowed() is false — i.e. from a Vert.x event-loop thread: inside a reactive REST endpoint that never leaves the IO thread, a Vert.x handler/worker-free route, a reactive gRPC/GraphQL resolver executing on the loop, or a messaging callback without @Blocking.","commonSituations":"Mixing reactive endpoints with blocking Hibernate; forgetting @Blocking or missing an @Transactional boundary that would dispatch to a worker thread; calling the EM from a Vert.x EventBus consumer or timer set directly on the event loop; Uni.createFrom().item(() -> em.find(...)) evaluated eagerly on the IO thread.","solutions":["Annotate the method with @Transactional (its interceptor runs the work on a worker thread) so blocking JDBC is legal there.","For reactive endpoints, add io.smallrye.common.annotation.Blocking to the resource method to shift execution to a worker thread.","Move the EntityManager call into a separate @ApplicationScoped bean method annotated @Transactional/@Blocking and call it from the reactive pipeline (e.g. Uni.emitOn or the CDI call itself dispatches).","Ensure lazy suppliers like Uni/CompletionStage bodies touching the EM actually execute on a worker thread, not during subscription on the event loop."],"exampleFix":"// before\n@Path(\"/users\")\npublic class UserResource {\n    @Inject EntityManager em;\n    @GET\n    public Uni<User> get(long id) {\n        return Uni.createFrom().item(em.find(User.class, id)); // BlockingOperationNotAllowedException\n    }\n}\n\n// after\n@Path(\"/users\")\npublic class UserResource {\n    @Inject UserRepository repo;\n    @GET\n    public Uni<User> get(long id) {\n        return repo.find(id); // runs on worker thread\n    }\n}\n\n@ApplicationScoped\nclass UserRepository {\n    @Inject EntityManager em;\n    @Transactional\n    public User find(long id) { return em.find(User.class, id); }\n}","handlingStrategy":"validation","validationCode":"import io.quarkus.vertx.core.runtime.context.BlockingOperationControl;\n\nboolean emSafeToCallHere() {\n    return BlockingOperationControl.isBlockingAllowed();\n}\n// Call before any EntityManager operation when unsure of the thread:\n// if (!emSafeToCallHere()) dispatchToWorkerThread(...);","typeGuard":null,"tryCatchPattern":"try {\n    em.find(User.class, id);\n} catch (BlockingOperationNotAllowedException e) {\n    // we were on the event loop: re-dispatch to a worker-thread bean\n    return Uni.createFrom().item(() -> transactionalRepo.find(id))\n        .runSubscriptionOn(Infrastructure.getDefaultWorkerPool())\n        .await().indefinitely();\n}","preventionTips":["Annotate blocking ORM entry points with @Transactional or @Blocking so Quarkus moves them to a worker thread.","Never touch the EntityManager inside Uni/CompletionStage suppliers that may run on the IO thread.","Keep reactive endpoints free of JDBC/ORM code; delegate to @ApplicationScoped transactional services.","Test reactive endpoints with RestAssured/real HTTP so they execute on the same thread model as production."],"tags":["blocking","event-loop","hibernate-orm","reactive","vertx"],"backgroundTag":"blocking-operation-not-allowed","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}