{"record":{"id":"f32b9829d74280fb","repo":"quarkusio/quarkus","slug":"no-vertx-context-found-f32b98","errorCode":null,"errorMessage":"No Vertx context found","messagePattern":"No Vertx context found","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"extensions/vertx/kotlin/runtime/src/main/kotlin/io/quarkus/vertx/kotlin/runtime/CoroutineInvoker.kt","lineNumber":22,"sourceCode":"import io.vertx.core.Vertx\nimport jakarta.enterprise.invoke.Invoker\nimport java.util.concurrent.CompletionStage\nimport kotlin.coroutines.suspendCoroutine\nimport kotlinx.coroutines.CoroutineDispatcher\nimport kotlinx.coroutines.async\nimport kotlinx.coroutines.future.asCompletableFuture\n\nobject CoroutineInvoker {\n    @JvmStatic\n    fun <T> inNewCoroutine(\n        instance: T,\n        arguments: Array<Any?>,\n        invoker: Invoker<T, Unit>,\n    ): CompletionStage<Void?> {\n        val coroutineScope = Arc.container().instance(ApplicationCoroutineScope::class.java).get()\n        val dispatcher: CoroutineDispatcher =\n            Vertx.currentContext()?.let(::VertxDispatcher)\n                ?: throw IllegalStateException(\"No Vertx context found\")\n\n        return coroutineScope\n            .async<Void?>(context = dispatcher) {\n                suspendCoroutine<Unit> { continuation ->\n                    val newArguments = arrayOfNulls<Any>(arguments.size + 1)\n                    arguments.copyInto(newArguments)\n                    newArguments[arguments.size] = continuation\n                    invoker.invoke(instance, newArguments)\n                }\n                null\n            }\n            .asCompletableFuture()\n    }\n}\n","sourceCodeStart":4,"sourceCodeEnd":37,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/vertx/kotlin/runtime/src/main/kotlin/io/quarkus/vertx/kotlin/runtime/CoroutineInvoker.kt#L4-L37","documentation":"The quarkus-vertx-kotlin extension invokes Kotlin suspend event consumers by launching a coroutine on a dispatcher bound to the current Vert.x duplicated context. CoroutineInvoker.inNewCoroutine requires Vertx.currentContext() to be non-null; if the invoker runs outside any Vert.x context, it throws IllegalStateException(\"No Vertx context found\").","triggerScenarios":"Invoking a Kotlin suspend @ConsumeEvent method's generated invoker from a thread with no Vert.x duplicated context attached — e.g. direct programmatic invoker.invoke() calls from a non-Vert.x thread, custom invoker customizers, or testing harnesses calling the bean method's invoker directly.","commonSituations":"Tests calling the consumer invoker outside the event bus; manual invocation of CDI invokers from scheduler/HTTP threads; running a suspend consumer where the Vert.x context was not propagated (e.g. blocking executor without context capture).","solutions":["Invoke the consumer normally through the event bus (vertx.eventBus().request/send) so a Vert.x context is attached","Use Vertx.getOrCreateContext()/runOnContext or context.runOnContext to wrap the invocation in a Vert.x context","In tests, use @RunOnVertxContext (quarkus-vertx test util) instead of calling the invoker directly","If invoking programmatically, capture and duplicate the Vertx context and run inside it"],"exampleFix":"// before\ninvoker.invoke(bean, args); // plain test thread\n\n// after\nvertx.runOnContext(v -> invoker.invoke(bean, args));","handlingStrategy":"validation","validationCode":"if (Vertx.currentContext() == null) {\n    throw new IllegalStateException(\"Invoke suspend consumers via the event bus or inside vertx.runOnContext\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    CoroutineInvoker.inNewCoroutine(instance, args, invoker);\n} catch (IllegalStateException e) {\n    if (e.message == \"No Vertx context found\") {\n        vertx.runOnContext(v -> invoker.invoke(instance, args));\n    } else throw e;\n}","preventionTips":["Always dispatch suspend @ConsumeEvent methods through the event bus","In tests use @RunOnVertxContext instead of calling invokers directly","Never call CDI invokers for suspend consumers from scheduler/worker threads without a Vert.x context"],"tags":["quarkus","vertx","kotlin","coroutines","duplicated-context"],"backgroundTag":"missing-vertx-context","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"}