quarkusio/quarkus · error · IllegalStateException

An event consumer business method that accepts io.vertx.core

Error message

An event consumer business method that accepts io.vertx.core.eventbus.Message or io.vertx.mutiny.core.eventbus.Message must return void [method: %s, bean:%s]

What it means

When a @ConsumeEvent method consumes the full io.vertx.core.eventbus.Message (or Mutiny Message) instead of just the payload, Quarkus requires it to return void. Message-consuming methods handle replies themselves via message.reply(); a non-void return type is ambiguous and rejected at build time.

Source

Thrown at extensions/vertx/deployment/src/main/java/io/quarkus/vertx/deployment/VertxProcessor.java:190

                    if (parametersCount == 2) {
                        if (!isMessageHeaders(params.get(0).name())) {
                            // If there are two parameters, the first must be message headers.
                            throw new IllegalStateException(String.format(
                                    "An event consumer business method with two parameters must have MultiMap as the first parameter: %s [method: %s, bean:%s]",
                                    params, method, bean));
                        } else if (isMessage(params.get(1).name())) {
                            throw new IllegalStateException(String.format(
                                    "An event consumer business method with two parameters must not accept io.vertx.core.eventbus.Message or io.vertx.mutiny.core.eventbus.Message: %s [method: %s, bean:%s]",
                                    params, method, bean));
                        }
                    } else if (parametersCount != 1) {
                        throw new IllegalStateException(String.format(
                                "An event consumer business method must accept exactly one parameter: %s [method: %s, bean:%s]",
                                params, method, bean));
                    }
                    if (method.returnType().kind() != Kind.VOID && VertxConstants.isMessage(params.get(0).name())
                            && !KotlinUtils.isKotlinSuspendMethod(method)) {
                        throw new IllegalStateException(String.format(
                                "An event consumer business method that accepts io.vertx.core.eventbus.Message or io.vertx.mutiny.core.eventbus.Message must return void [method: %s, bean:%s]",
                                method, bean));
                    }
                    if (method.hasAnnotation(RunOnVirtualThread.class) && consumeEvent.value("ordered") != null
                            && consumeEvent.value("ordered").asBoolean()) {
                        throw new IllegalStateException(String.format(
                                "An event consumer business method that cannot use @RunOnVirtualThread and set the ordered attribute to true [method: %s, bean:%s]",
                                method, bean));
                    }

                    InvokerBuilder builder = invokerFactory.createInvoker(bean, method)
                            .withInstanceLookup();

                    if (parametersCount == 1 && method.parameterType(0).name().equals(MESSAGE)) {
                        // io.vertx.core.eventbus.Message
                        // no transformation required
                    } else if (parametersCount == 1 && method.parameterType(0).name().equals(MUTINY_MESSAGE)) {
                        // io.vertx.mutiny.core.eventbus.Message

View on GitHub (pinned to e1c734241f)

Solutions

  1. Make the method return void and reply explicitly with message.reply(...)/message.fail(...)
  2. If you want to return a value, consume the raw payload instead of Message and let the returned object be the reply
  3. Convert to Uni<Void>/CompletionStage<Void> only via a payload-style method if async processing is needed
  4. For Kotlin, keep the method suspend — it is allowed despite non-void semantics

Example fix

// before
@ConsumeEvent("greeting")
String consume(Message<String> msg) { return "hi"; }

// after
@ConsumeEvent("greeting")
void consume(Message<String> msg) { msg.reply("hi"); }
Defensive patterns

Strategy: validation

Validate before calling

if ((param instanceof io.vertx.core.eventbus.Message
     || param instanceof io.vertx.mutiny.core.eventbus.Message)
    && method.getReturnType() != void.class) {
    throw new IllegalStateException("Message-consuming @ConsumeEvent methods must return void: " + method);
}

Prevention

When it happens

Trigger: A @ConsumeEvent method whose sole parameter is Message/Mutiny Message and whose return type is not void (e.g. returns String, Uni, or a payload object). Kotlin suspend methods are exempt.

Common situations: Migrating a payload-style consumer to Message style but keeping the return value; copying a payload consumer signature and swapping the parameter to Message; auto-complete generating a reply-returning method.

Related errors


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