{"record":{"id":"ebdc823ec73dd3cc","repo":"quarkusio/quarkus","slug":"not-a-coroutine-invoker","errorCode":null,"errorMessage":"Not a coroutine invoker","messagePattern":"Not a coroutine invoker","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"extensions/resteasy-reactive/rest-kotlin/runtime/src/main/kotlin/org/jboss/resteasy/reactive/server/runtime/kotlin/CoroutineInvocationHandler.kt","lineNumber":28,"sourceCode":"import org.jboss.resteasy.reactive.server.spi.ServerRestHandler\nimport org.slf4j.LoggerFactory\n\nprivate val logger = LoggerFactory.getLogger(CoroutineInvocationHandler::class.java)\n\nclass CoroutineInvocationHandler(\n    private val invoker: EndpointInvoker,\n    private val coroutineScope: CoroutineScope,\n) : ServerRestHandler {\n\n    private val originalTCCL: ClassLoader = Thread.currentThread().contextClassLoader\n\n    override fun handle(requestContext: ResteasyReactiveRequestContext) {\n        if (requestContext.result != null) {\n            return\n        }\n        if (invoker !is CoroutineEndpointInvoker) {\n            requestContext.handleException(IllegalStateException(\"Not a coroutine invoker\"), true)\n            return\n        }\n\n        val requestScope = requestContext.captureCDIRequestScope()\n        val dispatcher: CoroutineDispatcher =\n            Vertx.currentContext()?.let { VertxDispatcher(it, requestScope, requestContext) }\n                ?: throw IllegalStateException(\"No Vertx context found\")\n\n        logger.trace(\"Handling request with dispatcher {}\", dispatcher)\n\n        requestContext.suspend()\n        val done = AtomicBoolean()\n        val canceled = AtomicBoolean()\n\n        val job =\n            coroutineScope.launch(context = dispatcher) {\n                // ensure the proper CL is not lost in dev-mode\n                Thread.currentThread().contextClassLoader = originalTCCL\n                try {","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/resteasy-reactive/rest-kotlin/runtime/src/main/kotlin/org/jboss/resteasy/reactive/server/runtime/kotlin/CoroutineInvocationHandler.kt#L10-L46","documentation":"CoroutineInvocationHandler.handle runs after the endpoint method has been invoked. The generated invoker must implement CoroutineEndpointInvoker for Kotlin suspend endpoints; if the cached invoker is a different type, the handler flags IllegalStateException via handleException instead of crashing the request loop. This is an internal invariant violation, typically a codegen/dispatch mismatch.","triggerScenarios":"At runtime, requestContext.result is null and the `invoker` field is not an instance of CoroutineEndpointInvoker — i.e. a non-coroutine invoker was wired into a coroutine-handled endpoint.","commonSituations":"Mixed Kotlin/Java endpoint compilation where the Kotlin coroutine handler is applied to a Java-generated invoker; stale generated classes after adding/removing `suspend`; build cache corruption.","solutions":["Clean and rebuild the project (./mvnw clean install) to regenerate endpoint invokers","Verify the endpoint method is actually a Kotlin suspend fun and the rest-kotlin extension is on the classpath","Check for mixed deployment artifacts — remove stale target/ classes from previous builds"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"fun isCoroutineInvoker(invoker: Any): Boolean = invoker is CoroutineEndpointInvoker","tryCatchPattern":"try {\n    chain.next(requestContext)\n} catch (e: IllegalStateException) {\n    if (e.message == \"Not a coroutine invoker\") {\n        // rebuild artifacts: ./mvnw clean install and redeploy\n    }\n    throw e\n}","preventionTips":["Run ./mvnw clean after changing Kotlin endpoint signatures","Keep the rest-kotlin extension consistent across modules","Avoid mixing stale generated classes with new source"],"tags":["kotlin","coroutines","resteasy-reactive","codegen"],"backgroundTag":"invoker-type-mismatch","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}