{"record":{"id":"f235cfac9a2ff81f","repo":"quarkusio/quarkus","slug":"exactlyonce-on-method-methodname-outgoing-cha","errorCode":null,"errorMessage":"@ExactlyOnce on method ${methodName}: outgoing channel '${outgoingChannel}' is not managed by the Kafka connector","messagePattern":"@ExactlyOnce on method (.+?): outgoing channel '(.+?)' is not managed by the Kafka connector","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/smallrye-reactive-messaging-kafka/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/kafka/deployment/SmallRyeReactiveMessagingKafkaProcessor.java","lineNumber":223,"sourceCode":"\n            boolean isSuspend = method.parameterTypes().stream()\n                    .anyMatch(t -> t.name().equals(DotNames.CONTINUATION));\n            if (isSuspend) {\n                throw new IllegalArgumentException(\n                        \"@ExactlyOnce on method \" + methodName\n                                + \" does not support Kotlin suspend functions\");\n            }\n\n            String incomingChannel = incoming.value().asString();\n            String outgoingChannel = outgoing.value().asString();\n\n            if (!discoveryState.isKafkaConnector(channelsManagedByConnectors, true, incomingChannel)) {\n                throw new IllegalArgumentException(\n                        \"@ExactlyOnce on method \" + methodName\n                                + \": incoming channel '\" + incomingChannel + \"' is not managed by the Kafka connector\");\n            }\n            if (!discoveryState.isKafkaConnector(channelsManagedByConnectors, false, outgoingChannel)) {\n                throw new IllegalArgumentException(\n                        \"@ExactlyOnce on method \" + methodName\n                                + \": outgoing channel '\" + outgoingChannel + \"' is not managed by the Kafka connector\");\n            }\n\n            LOGGER.infof(\"Exactly-once processing detected on method %s#%s, \" +\n                    \"configuring channels '%s' (incoming) and '%s' (outgoing)\",\n                    method.declaringClass().name(), method.name(), incomingChannel, outgoingChannel);\n\n            // Auto-configure outgoing channel for transactions\n            produceRuntimeConfigurationDefaultBuildItem(discoveryState, defaultConfigProducer,\n                    getChannelOutgoingPropertyName(outgoingChannel, \"transactional.id\"),\n                    \"${quarkus.application.name}-\" + outgoingChannel);\n            produceRuntimeConfigurationDefaultBuildItem(discoveryState, defaultConfigProducer,\n                    getChannelOutgoingPropertyName(outgoingChannel, \"enable.idempotence\"), \"true\");\n            produceRuntimeConfigurationDefaultBuildItem(discoveryState, defaultConfigProducer,\n                    getChannelOutgoingPropertyName(outgoingChannel, \"acks\"), \"all\");\n\n            // Auto-configure incoming channel for exactly-once","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/smallrye-reactive-messaging-kafka/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/kafka/deployment/SmallRyeReactiveMessagingKafkaProcessor.java#L205-L241","documentation":"Exactly-once processing requires the produced record to be sent within the same Kafka transaction as the offset commit, which is only possible when the outgoing channel uses the Kafka connector. This build-time error reports that the @Outgoing channel is not Kafka-connector-managed.","triggerScenarios":"The @Outgoing channel name fails discoveryState.isKafkaConnector(channelsManagedByConnectors, false, channel) — e.g. configured for another connector or an in-memory emitter.","commonSituations":"Producing to an in-memory channel or AMQP/Pulsar outgoing channel while the incoming is Kafka, or a missing/incorrect connector property for the outgoing channel.","solutions":["Set mp.messaging.outgoing.<channel>.connector=smallrye-kafka with proper topic/acks settings.","Fix the channel name in @Outgoing to match the Kafka-configured channel.","Remove @ExactlyOnce if the pipeline is not fully Kafka-based."],"exampleFix":"// before\nmp.messaging.outgoing.out.connector=smallrye-in-memory\n\n// after\nmp.messaging.outgoing.out.connector=smallrye-kafka\nmp.messaging.outgoing.out.topic=out-topic","handlingStrategy":"validation","validationCode":"String connector = config.getValue(\"mp.messaging.outgoing.\" + channel + \".connector\", String.class);\nif (!\"smallrye-kafka\".equals(connector)) {\n    throw new IllegalStateException(\"outgoing channel must use smallrye-kafka for @ExactlyOnce\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set mp.messaging.outgoing.<ch>.connector=smallrye-kafka for exactly-once pipelines","Never mix non-Kafka outgoing channels with @ExactlyOnce","Keep both ends of the pipeline explicitly configured"],"tags":["kafka","reactive-messaging","configuration","exactly-once"],"backgroundTag":"channel-not-kafka-connector","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}