{"record":{"id":"eb3f53b154753edc","repo":"alibaba/spring-cloud-alibaba","slug":"transactionmqproducer-must-have-a-transactionliste","errorCode":null,"errorMessage":"TransactionMQProducer must have a TransactionListener !!! ","messagePattern":"TransactionMQProducer must have a TransactionListener !!! ","errorType":"exception","errorClass":"MessagingException","httpStatus":null,"severity":"error","filePath":"spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/outbound/RocketMQProducerMessageHandler.java","lineNumber":176,"sourceCode":"\t}\n\n\t@Override\n\tpublic boolean isRunning() {\n\t\treturn running;\n\t}\n\n\t@Override\n\tprotected void handleMessageInternal(Message<?> message) {\n\t\ttry {\n\t\t\torg.apache.rocketmq.common.message.Message mqMessage = RocketMQMessageConverterSupport\n\t\t\t\t\t.convertMessage2MQ(destination.getName(), message);\n\t\t\tSendResult sendResult;\n\t\t\tif (defaultMQProducer instanceof TransactionMQProducer translateMQProducer) {\n\t\t\t\tTransactionListener transactionListener = RocketMQBeanContainerCache\n\t\t\t\t\t\t.getBean(mqProducerProperties.getTransactionListener(),\n\t\t\t\t\t\t\t\tTransactionListener.class);\n\t\t\t\tif (transactionListener == null) {\n\t\t\t\t\tthrow new MessagingException(\n\t\t\t\t\t\t\t\"TransactionMQProducer must have a TransactionListener !!! \");\n\t\t\t\t}\n\t\t\t\ttranslateMQProducer.setTransactionListener(transactionListener);\n\t\t\t\tif (log.isDebugEnabled()) {\n\t\t\t\t\tlog.debug(\"send transaction message ->{}\", mqMessage);\n\t\t\t\t}\n\t\t\t\tsendResult = defaultMQProducer.sendMessageInTransaction(mqMessage,\n\t\t\t\t\t\tmessage.getHeaders().get(RocketMQConst.USER_TRANSACTIONAL_ARGS));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (log.isDebugEnabled()) {\n\t\t\t\t\tlog.debug(\"send message ->{}\", mqMessage);\n\t\t\t\t}\n\t\t\t\tsendResult = this.send(mqMessage, this.messageQueueSelector,\n\t\t\t\t\t\tmessage.getHeaders(), message);\n\t\t\t}\n\t\t\tif (log.isDebugEnabled()) {\n\t\t\t\tlog.debug(\"the message has sent,message={},sendResult={}\", mqMessage,","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/alibaba/spring-cloud-alibaba/blob/115d5901102009492e05d5ec18c3f79cad4077d0/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/outbound/RocketMQProducerMessageHandler.java#L158-L194","documentation":"In handleMessageInternal, when the producer is a TransactionMQProducer the handler looks up a TransactionListener bean by name (`mqProducerProperties.getTransactionListener()`) via RocketMQBeanContainerCache. If none resolves, it throws MessagingException - transactional sends require a listener to drive local-execute and check-back.","triggerScenarios":"producerType is set to Trans (so a TransactionMQProducer is built) but no TransactionListener bean is registered/resolvable under the configured `transactionListener` name.","commonSituations":"Set `producerType: Trans` without providing a `transactionListener` bean; bean name typo; the listener bean lives in a context RocketMQBeanContainerCache does not scan; a transaction example copied incompletely.","solutions":["Register a TransactionListener bean and reference its name via `spring.cloud.stream.rocketmq.bindings.<output>.producer.transactionListener=<beanName>`.","If you don't need transactions, set `producerType: Normal` (default).","Verify the bean is visible to RocketMQBeanContainerCache (registered in the application context)."],"exampleFix":"// before\nspring:\n  cloud:\n    stream:\n      rocketmq:\n        bindings:\n          txOut:\n            producer:\n              producerType: Trans   # no transactionListener -> [131]\n// after\n@Bean(\"myTxListener\")\nTransactionListener myTxListener() { /* ... */ return /* ... */; }\n// yaml:\nspring:\n  cloud:\n    stream:\n      rocketmq:\n        bindings:\n          txOut:\n            producer:\n              producerType: Trans\n              transactionListener: myTxListener","handlingStrategy":"validation","validationCode":"// Pre-flight: transactional producers must resolve a listener.\nif (RocketMQProducerProperties.ProducerType.Trans.equalsName(mqProducerProperties.getProducerType())) {\n    TransactionListener tl = RocketMQBeanContainerCache\n        .getBean(mqProducerProperties.getTransactionListener(), TransactionListener.class);\n    Assert.notNull(tl, \"transactionListener bean required for producerType=Trans (avoids [131])\");\n}","typeGuard":"// Type guard narrowing the producer type before send.\nboolean transactional = defaultMQProducer instanceof TransactionMQProducer;\nboolean hasListener = RocketMQBeanContainerCache\n    .getBean(mqProducerProperties.getTransactionListener(), TransactionListener.class) != null;\nif (transactional && !hasListener) {\n    throw new IllegalStateException(\"Trans producer requires a TransactionListener bean\");\n}","tryCatchPattern":null,"preventionTips":["Pair every `producerType: Trans` with a named TransactionListener bean.","Default to producerType Normal unless you need transactions.","Confirm bean visibility to RocketMQBeanContainerCache."],"tags":["rocketmq","producer","transaction","config","beans"],"backgroundTag":null,"analyzedSha":"115d5901102009492e05d5ec18c3f79cad4077d0","analyzedAt":"2026-08-14T04:47:13.900Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}