quarkusio/quarkus · error · IllegalStateException

No Vertx context found

Error message

No Vertx context found

What it means

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").

Source

Thrown at extensions/vertx/kotlin/runtime/src/main/kotlin/io/quarkus/vertx/kotlin/runtime/CoroutineInvoker.kt:22

import io.vertx.core.Vertx
import jakarta.enterprise.invoke.Invoker
import java.util.concurrent.CompletionStage
import kotlin.coroutines.suspendCoroutine
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.async
import kotlinx.coroutines.future.asCompletableFuture

object CoroutineInvoker {
    @JvmStatic
    fun <T> inNewCoroutine(
        instance: T,
        arguments: Array<Any?>,
        invoker: Invoker<T, Unit>,
    ): CompletionStage<Void?> {
        val coroutineScope = Arc.container().instance(ApplicationCoroutineScope::class.java).get()
        val dispatcher: CoroutineDispatcher =
            Vertx.currentContext()?.let(::VertxDispatcher)
                ?: throw IllegalStateException("No Vertx context found")

        return coroutineScope
            .async<Void?>(context = dispatcher) {
                suspendCoroutine<Unit> { continuation ->
                    val newArguments = arrayOfNulls<Any>(arguments.size + 1)
                    arguments.copyInto(newArguments)
                    newArguments[arguments.size] = continuation
                    invoker.invoke(instance, newArguments)
                }
                null
            }
            .asCompletableFuture()
    }
}

View on GitHub (pinned to e1c734241f)

Solutions

  1. Invoke the consumer normally through the event bus (vertx.eventBus().request/send) so a Vert.x context is attached
  2. Use Vertx.getOrCreateContext()/runOnContext or context.runOnContext to wrap the invocation in a Vert.x context
  3. In tests, use @RunOnVertxContext (quarkus-vertx test util) instead of calling the invoker directly
  4. If invoking programmatically, capture and duplicate the Vertx context and run inside it

Example fix

// before
invoker.invoke(bean, args); // plain test thread

// after
vertx.runOnContext(v -> invoker.invoke(bean, args));
Defensive patterns

Strategy: validation

Validate before calling

if (Vertx.currentContext() == null) {
    throw new IllegalStateException("Invoke suspend consumers via the event bus or inside vertx.runOnContext");
}

Try / catch

try {
    CoroutineInvoker.inNewCoroutine(instance, args, invoker);
} catch (IllegalStateException e) {
    if (e.message == "No Vertx context found") {
        vertx.runOnContext(v -> invoker.invoke(instance, args));
    } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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).

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/f32b9829d74280fb. Report an issue: GitHub.