quarkusio/quarkus · error · IllegalStateException
No Vertx context found. Consider using @NonBlocking on the c
Error message
No Vertx context found. Consider using @NonBlocking on the caller method, or make sure the upstream emits items on the Vert.x context
What it means
The coroutine invoker for a suspend Reactive Messaging method must run on a Vert.x context: it derives its dispatcher from Vertx.currentContext(). When invoked with no current Vertx context it throws IllegalStateException, advising @NonBlocking or ensuring upstream items are emitted on the Vert.x context.
Source
Thrown at extensions/smallrye-reactive-messaging/kotlin/src/main/kotlin/io/quarkus/smallrye/reactivemessaging/runtime/kotlin/AbstractSubscribingCoroutineInvoker.kt:16
package io.quarkus.smallrye.reactivemessaging.runtime.kotlin
import io.quarkus.arc.Arc
import io.smallrye.reactive.messaging.Invoker
import io.vertx.core.Vertx
import java.util.concurrent.CompletableFuture
import kotlinx.coroutines.async
import kotlinx.coroutines.future.asCompletableFuture
abstract class AbstractSubscribingCoroutineInvoker(private val beanInstance: Any) : Invoker {
override fun invoke(vararg args: Any?): CompletableFuture<Any?> {
val coroutineScope = Arc.container().instance(ApplicationCoroutineScope::class.java).get()
val dispatcher =
Vertx.currentContext()?.let(::VertxDispatcher)
?: throw IllegalStateException(
"No Vertx context found. Consider using @NonBlocking on the caller method, or make sure the upstream emits items on the Vert.x context"
)
return coroutineScope
.async(context = dispatcher) {
try {
invokeBean(beanInstance, args)
} finally {
dispatcher.cleanup()
}
}
.asCompletableFuture()
}
abstract suspend fun invokeBean(beanInstance: Any, args: Array<out Any?>): Any?
}
View on GitHub (pinned to e1c734241f)
Solutions
- Annotate the calling method with @NonBlocking so it runs on the Vert.x (event-loop) context.
- Make sure the upstream publisher emits on a Vert.x context (use runSubscriptionOn / emit on event loop).
- Remove @Blocking from the suspend method; @Blocking runs it on a worker thread without Vert.x context.
Example fix
// before
@Blocking
@Incoming("in")
suspend fun handle(p: String) { ... }
// after
@NonBlocking
@Incoming("in")
suspend fun handle(p: String) { ... } Defensive patterns
Strategy: validation
Validate before calling
// Guard in the invoker before starting the coroutine:
if (Vertx.currentContext() == null) {
throw IllegalStateException("invoke must be called on a Vert.x context")
} Try / catch
try {
invoker.invoke(args).get()
} catch (e: ExecutionException) {
val cause = e.cause
if (cause is IllegalStateException && cause.message?.contains("No Vertx context") == true) {
// rerun on a Vert.x duplicated context
vertx.runOnContext { invoker.invoke(args) }
} else throw cause
} Prevention
- Annotate coroutine mediators (or their callers) with @NonBlocking.
- Avoid @Blocking on suspend methods.
- Emit upstream items on the Vert.x context (e.g. Multi.createFrom().emitter with runSubscriptionOn the Vert.x executor).
When it happens
Trigger: A suspend @Incoming mediator invoked from a thread without a Vert.x duplicated context, e.g. a custom executor, plain worker thread, or non-blocking requirement violated by @Blocking upstream.
Common situations: Calling the invoker manually in tests; upstream emitter running on a non-Vert.x thread (e.g. timer/scheduled executor); misusing @Blocking on the coroutine method.
Related errors
- No Vertx context found
- No Vertx context found
- No Vertx context found
- Currently suspend methods for Reactive Messaging are not sup
- Method ${class}.${method} is suspendable but kotlinx-corouti
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/886207a8ac3ee137.
Report an issue: GitHub.