{"record":{"id":"8dad041c2ede8897","repo":"apache/rocketmq","slug":"send-request-message-to-fail","errorCode":null,"errorMessage":"send request message to <{}> fail","messagePattern":"send request message to <(.+?)> fail","errorType":"exception","errorClass":"MQClientException","httpStatus":null,"severity":"error","filePath":"client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java","lineNumber":1777,"sourceCode":"                    requestResponseFuture.setCause(e);\n                }\n            }, null, timeout - cost);\n\n            return waitResponse(msg, timeout, requestResponseFuture, cost);\n        } finally {\n            RequestFutureHolder.getInstance().getRequestFutureTable().remove(correlationId);\n        }\n    }\n\n    private Message waitResponse(Message msg, long timeout, RequestResponseFuture requestResponseFuture,\n        long cost) throws InterruptedException, RequestTimeoutException, MQClientException {\n        Message responseMessage = requestResponseFuture.waitResponseMessage(timeout - cost);\n        if (responseMessage == null) {\n            if (requestResponseFuture.isSendRequestOk()) {\n                throw new RequestTimeoutException(ClientErrorCode.REQUEST_TIMEOUT_EXCEPTION,\n                    \"send request message to <\" + msg.getTopic() + \"> OK, but wait reply message timeout, \" + timeout + \" ms.\");\n            } else {\n                throw new MQClientException(\"send request message to <\" + msg.getTopic() + \"> fail\", requestResponseFuture.getCause());\n            }\n        }\n        return responseMessage;\n    }\n\n    public void request(final Message msg, final MessageQueue mq, final RequestCallback requestCallback, long timeout)\n        throws RemotingException, InterruptedException, MQClientException, MQBrokerException {\n        long beginTimestamp = System.currentTimeMillis();\n        prepareSendRequest(msg, timeout);\n        final String correlationId = msg.getProperty(MessageConst.PROPERTY_CORRELATION_ID);\n\n        final RequestResponseFuture requestResponseFuture = new RequestResponseFuture(correlationId, timeout, requestCallback);\n        RequestFutureHolder.getInstance().getRequestFutureTable().put(correlationId, requestResponseFuture);\n\n        long cost = System.currentTimeMillis() - beginTimestamp;\n        this.sendKernelImpl(msg, mq, CommunicationMode.ASYNC, new SendCallback() {\n            @Override\n            public void onSuccess(SendResult sendResult) {","sourceCodeStart":1759,"sourceCodeEnd":1795,"githubUrl":"https://github.com/apache/rocketmq/blob/293f5885719fc4aa3619446a1900f58ccfcfdd29/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java#L1759-L1795","documentation":"MQClientException thrown by waitResponse when the reply future times out with no response AND the original request send did not succeed (isSendRequestOk() == false). The cause attached is whatever exception failed the request send, surfaced via RequestResponseFuture.getCause(). In other words: unlike error 295, the request never reliably reached the broker, so waiting for a reply is pointless.","triggerScenarios":"producer.request(msg, timeout) where the underlying send callback reported an exception: no route for the request topic, broker rejection, remoting failure — then the future times out and this wrapper reports the stored cause.","commonSituations":"Request topic not created (no route) on fresh deployments; broker briefly unavailable during request() so send fails; message properties (correlation id / reply-to) stripped by an interceptor causing send-side failure.","solutions":["Inspect getCause() of this MQClientException — it holds the real send failure (route missing, broker error, remoting exception).","If cause indicates 'No route info', create/verify the request topic and warm route caches before serving traffic.","For transient remoting causes, retry the whole request() with the same idempotency key; unlike the timeout case, the request never landed, so retry is safe.","Ensure producer interceptors preserve MessageConst.PROPERTY_CORRELATION_ID and reply-to properties."],"exampleFix":"// before\ntry { Message r = producer.request(msg, 3000L); }\ncatch (MQClientException e) { log.error(e.getMessage()); } // 'send request message to <t> fail'\n\n// after\ntry { Message r = producer.request(msg, 3000L); }\ncatch (MQClientException e) {\n    Throwable cause = e.getCause();\n    if (cause != null && cause.getMessage() != null && cause.getMessage().contains(\"No route info\")) {\n        topicProvisioner.ensureTopic(msg.getTopic()); // then retry once\n    } else {\n        retryQueue.add(msg); // transient send failure: safe to retry (request not delivered)\n    }\n}","handlingStrategy":"try-catch","validationCode":"// ensure route for the request topic exists before RPC\nif (producer.fetchPublishMessageQueues(msg.getTopic()).isEmpty()) {\n    throw new IllegalStateException(\"request topic \" + msg.getTopic() + \" has no route\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    Message reply = producer.request(msg, timeout);\n} catch (MQClientException e) { // 'send request message to <t> fail'\n    Throwable cause = e.getCause();\n    if (isTransient(cause)) {\n        producer.request(msg, timeout); // request never landed: retry is safe\n    } else {\n        throw new IllegalStateException(\"request send failed\", cause);\n    }\n}","preventionTips":["Always inspect getCause() here; the top-level message only says the request failed.","Distinguish this (send failed, safe to retry) from RequestTimeoutException (delivered, retry cautiously).","Ensure interceptors preserve correlation-id and reply-to properties on request messages."],"tags":["rocketmq","producer","request-reply","send-failure","rpc"],"backgroundTag":null,"analyzedSha":"293f5885719fc4aa3619446a1900f58ccfcfdd29","analyzedAt":"2026-08-14T11:50:13.822Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}