quarkusio/quarkus · error · ConfigurationException

The method `${method}` is using `@Keyed` but the annotated p

Error message

The method `${method}` is using `@Keyed` but the annotated parameter is not a `KeyedMulti`

What it means

@Keyed is only valid on a parameter whose type is a parameterized KeyedMulti<K, V>. At build time, handleKeyedMulti checks the annotated parameter's type; if it is any other type, the build fails with this ConfigurationException.

Source

Thrown at extensions/smallrye-reactive-messaging/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/deployment/QuarkusMediatorConfigurationUtil.java:286

        }

        return configuration;
    }

    private static void handleKeyedMulti(MethodInfo methodInfo,
            RecorderContext recorderContext, QuarkusMediatorConfiguration configuration) {
        if (methodInfo.parametersCount() == 1) { // @Keyed can only be used with a single parameter, a keyed multi
            var info = methodInfo.parameters().get(0);
            var annotation = info.annotation(ReactiveMessagingDotNames.KEYED);
            if (annotation != null) {
                // Make sure we have a keyed multi and an incoming.
                if (methodInfo.annotation(INCOMING) == null && methodInfo.annotation(INCOMINGS) == null) {
                    throw new ConfigurationException(
                            "The method `" + methodInfo.name() + "` is using `@Keyed` but is not annotated with `@Incoming`");
                }
                if (info.type().kind() != Type.Kind.PARAMETERIZED_TYPE
                        || !info.type().asParameterizedType().name().equals(ReactiveMessagingDotNames.KEYED_MULTI)) {
                    throw new ConfigurationException("The method `" + methodInfo.name()
                            + "` is using `@Keyed` but the annotated parameter is not a `KeyedMulti`");
                }
                var extractor = (Class<? extends KeyValueExtractor>) recorderContext
                        .classProxy(annotation.value().asClass().name().toString());
                configuration.setKeyed(extractor);
            }
            if (info.type().kind() == Type.Kind.PARAMETERIZED_TYPE
                    && info.type().asParameterizedType().name().equals(ReactiveMessagingDotNames.KEYED_MULTI)) {
                var args = info.type().asParameterizedType().arguments();
                configuration.setKeyType(recorderContext.classProxy(args.get(0).name().toString()));
                configuration.setValueType(recorderContext.classProxy(args.get(1).name().toString()));
            }
        }
    }

    // TODO: avoid hard coding CompletionStage handling
    private static Type determineReturnTypeOfSuspendMethod(MethodInfo methodInfo) {
        Type lastParamType = methodInfo.parameterType(methodInfo.parametersCount() - 1);

View on GitHub (pinned to e1c734241f)

Solutions

  1. Change the annotated parameter type to KeyedMulti<K, V> with explicit type parameters, e.g. KeyedMulti<String, Order>
  2. Remove @Keyed if the stream is not a keyed multi
  3. Ensure the first parameter (the @Keyed one) is the KeyedMulti itself per the API contract

Example fix

// before
void process(@Keyed Multi<Order> orders) { ... }
// after
@Incoming("orders")
void process(@Keyed KeyedMulti<String, Order> orders) { ... }
Defensive patterns

Strategy: validation

Validate before calling

Parameter p = method.getParameters()[0];
if (p.isAnnotationPresent(Keyed.class)
    && !(p.getType() instanceof ParameterizedType
         && ((ParameterizedType) p.getType()).getRawType() == KeyedMulti.class)) {
    throw new IllegalStateException("@Keyed parameter must be KeyedMulti<K,V>");
}

Prevention

When it happens

Trigger: Using @Keyed on a parameter typed Multi<V>, List<V>, a plain type, or a raw KeyedMulti without type parameters instead of KeyedMulti<String, Payload> (or another key type).

Common situations: Migrating from a Multi-based keyed pattern to KeyedMulti; forgetting type arguments on KeyedMulti; copy-pasting @Keyed onto the wrong parameter.

Related errors


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