{"record":{"id":"a6b5202838036fa2","repo":"apache/rocketmq","slug":"tranexecutor-is-null","errorCode":null,"errorMessage":"tranExecutor is null","messagePattern":"tranExecutor is null","errorType":"exception","errorClass":"MQClientException","httpStatus":null,"severity":"error","filePath":"client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java","lineNumber":1438,"sourceCode":"\n    /**\n     * SELECT ONEWAY -------------------------------------------------------\n     */\n    public void sendOneway(Message msg, MessageQueueSelector selector, Object arg)\n        throws MQClientException, RemotingException, InterruptedException {\n        try {\n            this.sendSelectImpl(msg, selector, arg, CommunicationMode.ONEWAY, null, this.defaultMQProducer.getSendMsgTimeout());\n        } catch (MQBrokerException e) {\n            throw new MQClientException(\"unknown exception\", e);\n        }\n    }\n\n    public TransactionSendResult sendMessageInTransaction(final Message msg,\n        final TransactionListener localTransactionListener, final Object arg)\n        throws MQClientException {\n        TransactionListener transactionListener = getCheckListener();\n        if (null == localTransactionListener && null == transactionListener) {\n            throw new MQClientException(\"tranExecutor is null\", null);\n        }\n\n        ensureNotDelayedForTransactional(msg);\n        Validators.checkMessage(msg, this.defaultMQProducer);\n\n        SendResult sendResult = null;\n        MessageAccessor.putProperty(msg, MessageConst.PROPERTY_TRANSACTION_PREPARED, \"true\");\n        MessageAccessor.putProperty(msg, MessageConst.PROPERTY_PRODUCER_GROUP, this.defaultMQProducer.getProducerGroup());\n        try {\n            sendResult = this.send(msg);\n        } catch (Exception e) {\n            throw new MQClientException(\"send message Exception\", e);\n        }\n\n        LocalTransactionState localTransactionState = LocalTransactionState.UNKNOW;\n        Throwable localException = null;\n        switch (sendResult.getSendStatus()) {\n            case SEND_OK: {","sourceCodeStart":1420,"sourceCodeEnd":1456,"githubUrl":"https://github.com/apache/rocketmq/blob/293f5885719fc4aa3619446a1900f58ccfcfdd29/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java#L1420-L1456","documentation":"Thrown by sendMessageInTransaction when both the passed-in localTransactionListener is null and the producer's internal check listener (getCheckListener()) is null. At least one listener must exist: the local one executes the local transaction branch, the internal one answers broker transaction-status checks. With neither, the transactional protocol cannot proceed.","triggerScenarios":"Calling producer.sendMessageInTransaction(msg, null, arg) on a DefaultMQProducer (or a subclass like TransactionMQProducer whose transactionListener was never set), so both listener references are null.","commonSituations":"Migrating code from TransactionMQProducer to DefaultMQProducer and dropping setTransactionListener; Spring bean wiring where the listener field is optional and silently null; forgetting that the check listener is only installed when a TransactionListener was configured before start().","solutions":["Pass a non-null TransactionListener as the second argument of sendMessageInTransaction.","Or, if you want broker-driven transaction checks, set the listener on the producer before start(): ((TransactionMQProducer) producer).setTransactionListener(listener).","Fail fast at wiring time: assert the listener is non-null right after producer construction rather than at first send.","Do not reuse one producer for both plain and transactional sends if the transactional listener wiring is conditional."],"exampleFix":"// before\nTransactionSendResult r = producer.sendMessageInTransaction(msg, null, arg);\n\n// after\nTransactionListener listener = new TransactionListener() {\n    public LocalTransactionState executeLocalTransaction(Message m, Object a) { /* commit DB tx */ return LocalTransactionState.COMMIT_MESSAGE; }\n    public LocalTransactionState checkLocalTransaction(MessageExt m) { return LocalTransactionState.COMMIT_MESSAGE; }\n};\nTransactionSendResult r = producer.sendMessageInTransaction(msg, listener, arg);","handlingStrategy":"validation","validationCode":"Objects.requireNonNull(localTransactionListener,\n    \"TransactionListener required for sendMessageInTransaction\");\n// also assert producer wiring if you rely on check-backs\nif (producer instanceof TransactionMQProducer tp\n        && tp.getTransactionListener() == null && localTransactionListener == null) {\n    throw new IllegalStateException(\"no transaction listener configured\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    producer.sendMessageInTransaction(msg, listener, arg);\n} catch (MQClientException e) {\n    if (\"tranExecutor is null\".equals(e.getMessage())) {\n        throw new IllegalStateException(\"transaction listener wiring missing\", e); // config bug, fail fast\n    }\n    throw e;\n}","preventionTips":["Set the TransactionListener at producer construction time, never conditionally.","Assert listener presence in a startup self-check so wiring bugs surface at boot, not first send.","Keep transactional producers dedicated; don't share them with plain-send code paths."],"tags":["rocketmq","producer","transactional-message","null-listener","configuration"],"backgroundTag":null,"analyzedSha":"293f5885719fc4aa3619446a1900f58ccfcfdd29","analyzedAt":"2026-08-14T11:50:13.822Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}