quarkusio/quarkus · error · IllegalStateException

An event consumer business method with two parameters must n

Error message

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]

What it means

Companion validation to 2508: a two-parameter @ConsumeEvent method may declare (MultiMap headers, payload) but must not also accept an eventbus Message as the second parameter, since the Message would consume the whole event leaving nothing for headers. The build fails naming the parameters, method, and bean.

Source

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

                    continue;
                }
                AnnotationInstance consumeEvent = annotationStore.getAnnotation(method, CONSUME_EVENT);
                if (consumeEvent != null) {
                    // Validate method params and return type
                    int parametersCount = method.parametersCount();
                    if (KotlinUtils.isKotlinSuspendMethod(method)) {
                        parametersCount--;
                    }

                    List<Type> params = method.parameterTypes();
                    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]",

View on GitHub (pinned to e1c734241f)

Solutions

  1. Use (MultiMap headers, T payload) — read payload directly, not via Message
  2. Or keep a single Message<T> parameter and access msg.headers() inside
  3. Split logic: a single-Message consumer that inspects headers internally

Example fix

// before
@ConsumeEvent("addr")
public void on(MultiMap headers, Message<String> msg) { }
// after
@ConsumeEvent("addr")
public void on(MultiMap headers, String payload) { }
// or
@ConsumeEvent("addr")
public void on(Message<String> msg) { /* msg.headers() */ }
Defensive patterns

Strategy: validation

Validate before calling

// forbid Message as second parameter of two-param consumers
for (Method m : MyConsumer.class.getDeclaredMethods()) {
    if (m.isAnnotationPresent(ConsumeEvent.class) && m.getParameterCount() == 2) {
        Class<?> second = m.getParameterTypes()[1];
        if (io.vertx.core.eventbus.Message.class.isAssignableFrom(second)
            || io.vertx.mutiny.core.eventbus.Message.class.isAssignableFrom(second))
            throw new IllegalStateException("Second parameter must be a payload, not Message: " + m);
    }
}

Prevention

When it happens

Trigger: Declaring method(MultiMap headers, Message<T> msg) on a @ConsumeEvent method.

Common situations: Developer wants both headers and the full Message; porting code that used a single Message parameter and adding headers incorrectly.

Related errors


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