{"record":{"id":"b598c4759936b017","repo":"quarkusio/quarkus","slug":"blocking-grpc-client-call-made-from-the-event-loop","errorCode":null,"errorMessage":"Blocking gRPC client call made from the event loop. If the code is executed from a gRPC service or a RESTEasy Reactive resource, either annotate the method  that makes the call with `@Blocking` or use the non-blocking client.","messagePattern":"Blocking gRPC client call made from the event loop\\. If the code is executed from a gRPC service or a RESTEasy Reactive resource, either annotate the method  that makes the call with `@Blocking` or use the non-blocking client\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"extensions/grpc/runtime/src/main/java/io/quarkus/grpc/runtime/supports/EventLoopBlockingCheckInterceptor.java","lineNumber":15,"sourceCode":"package io.quarkus.grpc.runtime.supports;\n\nimport io.grpc.CallOptions;\nimport io.grpc.Channel;\nimport io.grpc.ClientCall;\nimport io.grpc.ClientInterceptor;\nimport io.grpc.MethodDescriptor;\nimport io.vertx.core.Context;\n\npublic class EventLoopBlockingCheckInterceptor implements ClientInterceptor {\n    @Override\n    public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method, CallOptions callOptions,\n            Channel next) {\n        if (Context.isOnEventLoopThread()) {\n            throw new IllegalStateException(\"Blocking gRPC client call made from the event loop. \" +\n                    \"If the code is executed from a gRPC service or a RESTEasy Reactive resource, either annotate the method \" +\n                    \" that makes the call with `@Blocking` or use the non-blocking client.\");\n        }\n        return next.newCall(method, callOptions);\n    }\n}\n","sourceCodeStart":1,"sourceCodeEnd":22,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/grpc/runtime/src/main/java/io/quarkus/grpc/runtime/supports/EventLoopBlockingCheckInterceptor.java#L1-L22","documentation":"EventLoopBlockingCheckInterceptor is a gRPC client interceptor that detects blocking client calls made on an event-loop thread, which would stall other requests sharing that thread. When Context.isOnEventLoopThread() is true it throws IllegalStateException, advising to use @Blocking or the non-blocking (mutiny) client.","triggerScenarios":"Invoking a blocking gRPC stub method (blocking variant of a Quarkus gRPC client) from inside a method running on an event-loop thread — e.g. from a reactive gRPC service method, a RESTEasy Reactive resource method, or a vertx event-loop callback.","commonSituations":"Calling blockingService.method() inside a @GET reactive endpoint; awaiting a gRPC call inside a Mutiny pipeline on the event loop; legacy blocking code moved into a reactive handler.","solutions":["Annotate the calling method with @Blocking so it runs on a worker thread","Use the Mutiny (non-blocking) stub instead of the blocking stub and compose with Uni/Multi","Move the blocking call off the event loop (e.g. execute on an executor)","Ensure @RunOnVirtualThread/@Blocking semantics fit before catching/suppressing"],"exampleFix":"// before\n@GET\npublic Uni<String> get() {\n    return Uni.createFrom().item(blockingStub.sayHello(req).getMessage()); // event loop!\n}\n// after\n@GET\npublic Uni<String> get() {\n    return mutinyStub.sayHello(req).map(HelloReply::getMessage);\n}","handlingStrategy":"try-catch","validationCode":"if (Context.isOnEventLoopThread() && usingBlockingStub) {\n    LOG.warn(\"Blocking gRPC call about to run on event loop; switch to Mutiny stub or @Blocking\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    return blockingStub.sayHello(req);\n} catch (IllegalStateException e) {\n    if (e.getMessage().startsWith(\"Blocking gRPC client call\")) {\n        throw new ServerWebApplicationException(\"Use non-blocking client\", 500);\n    }\n    throw e;\n}","preventionTips":["Prefer Mutiny stubs in reactive endpoints","Annotate methods performing blocking calls with @Blocking","Check Context.isOnEventLoopThread() in dev-mode tests"],"tags":["grpc","event-loop","blocking","reactive","quarkus"],"backgroundTag":"blocking-call-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"}