{"record":{"id":"1ff009d1880805bd","repo":"quarkusio/quarkus","slug":"the-method-method-is-using-keyed-but-is-no","errorCode":null,"errorMessage":"The method `${method}` is using `@Keyed` but is not annotated with `@Incoming`","messagePattern":"The method `(.+?)` is using `@Keyed` but is not annotated with `@Incoming`","errorType":"validation","errorClass":"ConfigurationException","httpStatus":null,"severity":"error","filePath":"extensions/smallrye-reactive-messaging/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/deployment/QuarkusMediatorConfigurationUtil.java","lineNumber":281,"sourceCode":"                configuration.setBlockingExecutionOrdered(false);\n                configuration.setWorkerPoolName(QuarkusWorkerPoolRegistry.DEFAULT_VIRTUAL_THREAD_WORKER);\n            } else {\n                configuration.setBlockingExecutionOrdered(true);\n            }\n        }\n\n        return configuration;\n    }\n\n    private static void handleKeyedMulti(MethodInfo methodInfo,\n            RecorderContext recorderContext, QuarkusMediatorConfiguration configuration) {\n        if (methodInfo.parametersCount() == 1) { // @Keyed can only be used with a single parameter, a keyed multi\n            var info = methodInfo.parameters().get(0);\n            var annotation = info.annotation(ReactiveMessagingDotNames.KEYED);\n            if (annotation != null) {\n                // Make sure we have a keyed multi and an incoming.\n                if (methodInfo.annotation(INCOMING) == null && methodInfo.annotation(INCOMINGS) == null) {\n                    throw new ConfigurationException(\n                            \"The method `\" + methodInfo.name() + \"` is using `@Keyed` but is not annotated with `@Incoming`\");\n                }\n                if (info.type().kind() != Type.Kind.PARAMETERIZED_TYPE\n                        || !info.type().asParameterizedType().name().equals(ReactiveMessagingDotNames.KEYED_MULTI)) {\n                    throw new ConfigurationException(\"The method `\" + methodInfo.name()\n                            + \"` is using `@Keyed` but the annotated parameter is not a `KeyedMulti`\");\n                }\n                var extractor = (Class<? extends KeyValueExtractor>) recorderContext\n                        .classProxy(annotation.value().asClass().name().toString());\n                configuration.setKeyed(extractor);\n            }\n            if (info.type().kind() == Type.Kind.PARAMETERIZED_TYPE\n                    && info.type().asParameterizedType().name().equals(ReactiveMessagingDotNames.KEYED_MULTI)) {\n                var args = info.type().asParameterizedType().arguments();\n                configuration.setKeyType(recorderContext.classProxy(args.get(0).name().toString()));\n                configuration.setValueType(recorderContext.classProxy(args.get(1).name().toString()));\n            }\n        }","sourceCodeStart":263,"sourceCodeEnd":299,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/smallrye-reactive-messaging/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/deployment/QuarkusMediatorConfigurationUtil.java#L263-L299","documentation":"In Reactive Messaging, @Keyed marks a parameter for keyed processing of a KeyedMulti stream, which only makes sense on an @Incoming consumer method. At build time, handleKeyedMulti rejects any method using @Keyed without @Incoming/@Incomings with a ConfigurationException.","triggerScenarios":"Annotating a method parameter with @Keyed on a method that lacks @Incoming (e.g. an @Outgoing producer, a plain method, or a typo in the @Incoming annotation import).","commonSituations":"Copy-pasting @Keyed from a consumer to a producer; mixing io.smallrye.reactive.messaging.annotations.Incoming with a wrong import; refactoring that removed @Incoming while keeping @Keyed.","solutions":["Add @Incoming(\"channel\") to the method that uses @Keyed","Remove @Keyed if the method is not a message consumer","Verify the @Incoming import is io.smallrye.reactive.messaging.Incoming and the annotation was not accidentally removed"],"exampleFix":"// before\n@Keyed String key, Multi<MyEvent> events\n// after\n@Incoming(\"events\")\nvoid process(@Keyed String key, KeyedMulti<String, MyEvent> events) { ... }","handlingStrategy":"validation","validationCode":"if (method.getAnnotation(Keyed.class) != null\n    && method.getAnnotation(Incoming.class) == null\n    && method.getAnnotation(Incomings.class) == null) {\n    throw new IllegalStateException(\"@Keyed requires @Incoming\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only apply @Keyed to @Incoming consumer methods","Check imports — use io.smallrye.reactive.messaging annotations consistently","Run the build early; this is caught at augmentation time, not runtime"],"tags":["reactive-messaging","build-time-validation","annotations"],"backgroundTag":"missing-required-annotation","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"}