quarkusio/quarkus · error · IllegalStateException
No Vertx context found
Error message
No Vertx context found
What it means
FlowToPublisherHandler adapts a Kotlin Flow result into a reactive Publisher for RESTEasy Reactive. It needs the Vert.x context to construct a VertxDispatcher; if Vertx.currentContext() is null it throws IllegalStateException("No Vertx context found"). Same family as the coroutine handler context error but on the Flow-to-Publisher path.
Source
Thrown at extensions/resteasy-reactive/rest-kotlin/runtime/src/main/kotlin/org/jboss/resteasy/reactive/server/runtime/kotlin/FlowToPublisherHandler.kt:23
import jakarta.enterprise.inject.spi.CDI
import java.util.concurrent.Executor
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext
import org.jboss.resteasy.reactive.server.spi.ServerRestHandler
class FlowToPublisherHandler : ServerRestHandler {
private val originalTCCL: ClassLoader = Thread.currentThread().contextClassLoader
override fun handle(requestContext: ResteasyReactiveRequestContext?) {
val result = requestContext!!.result
if (result is Flow<*>) {
val requestScope = requestContext.captureCDIRequestScope()
val dispatcher: CoroutineDispatcher =
Vertx.currentContext()?.let { VertxDispatcher(it, requestScope, requestContext) }
?: throw IllegalStateException("No Vertx context found")
val coroutineScope = CDI.current().select(ApplicationCoroutineScope::class.java)
requestContext.suspend()
coroutineScope.get().launch(context = dispatcher) {
// ensure the proper CL is not lost in dev-mode
Thread.currentThread().contextClassLoader = originalTCCL
requestContext.result = result.asMulti()
// run in a direct invocation executor to run the rest of the invocation in the
// co-route scope
// feels a bit fragile, but let's see how it goes
requestContext.resume(Executor { it.run() })
}
}
}
}
View on GitHub (pinned to e1c734241f)
Solutions
- Ensure Flow-returning endpoints are served via the standard HTTP pipeline on Vert.x event loops
- Avoid @Blocking on Flow-returning endpoints
- Call endpoints through HTTP/RestAssured in tests instead of direct method invocation
- Upgrade Quarkus for improved context propagation
Example fix
// before
@Blocking
@GET
fun stream(): Flow<Item> = flow { ... }
// after
@GET
fun stream(): Flow<Item> = flow { ... } Defensive patterns
Strategy: try-catch
Validate before calling
if (io.vertx.core.Vertx.currentContext() == null) {
throw IllegalStateException("Flow endpoint handled without Vert.x context")
} Type guard
fun canAdaptFlow(): Boolean = io.vertx.core.Vertx.currentContext() != null
Try / catch
try {
flowHandler.handle(requestContext)
} catch (e: IllegalStateException) {
if (e.message?.contains("No Vertx context found") == true) {
requestContext.handleException(e, true)
} else throw e
} Prevention
- Do not annotate Flow-returning endpoints with @Blocking
- Test Flow endpoints through HTTP, not direct invocation
- Keep threading/dispatch customizations within Vert.x context propagation rules
When it happens
Trigger: An endpoint returning Flow<...> is processed on a thread without an active Vert.x context, so VertxDispatcher cannot be created.
Common situations: Flow-returning endpoints invoked via blocking dispatch or custom thread pools; tests calling resource methods directly; threading extensions stripping the Vert.x context before result handling.
Related errors
- No Vertx context found
- No Vertx context found
- No Vertx context found
- MultiByteHttpData invoked on an invalid context :
- Attempting a blocking write on io thread
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/febb3cb1a29bd9dd.
Report an issue: GitHub.