apache/rocketmq · error · MQClientException
send request message to <{}> fail
Error message
send request message to <{}> fail What it means
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.
Source
Thrown at client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java:1777
requestResponseFuture.setCause(e);
}
}, null, timeout - cost);
return waitResponse(msg, timeout, requestResponseFuture, cost);
} finally {
RequestFutureHolder.getInstance().getRequestFutureTable().remove(correlationId);
}
}
private Message waitResponse(Message msg, long timeout, RequestResponseFuture requestResponseFuture,
long cost) throws InterruptedException, RequestTimeoutException, MQClientException {
Message responseMessage = requestResponseFuture.waitResponseMessage(timeout - cost);
if (responseMessage == null) {
if (requestResponseFuture.isSendRequestOk()) {
throw new RequestTimeoutException(ClientErrorCode.REQUEST_TIMEOUT_EXCEPTION,
"send request message to <" + msg.getTopic() + "> OK, but wait reply message timeout, " + timeout + " ms.");
} else {
throw new MQClientException("send request message to <" + msg.getTopic() + "> fail", requestResponseFuture.getCause());
}
}
return responseMessage;
}
public void request(final Message msg, final MessageQueue mq, final RequestCallback requestCallback, long timeout)
throws RemotingException, InterruptedException, MQClientException, MQBrokerException {
long beginTimestamp = System.currentTimeMillis();
prepareSendRequest(msg, timeout);
final String correlationId = msg.getProperty(MessageConst.PROPERTY_CORRELATION_ID);
final RequestResponseFuture requestResponseFuture = new RequestResponseFuture(correlationId, timeout, requestCallback);
RequestFutureHolder.getInstance().getRequestFutureTable().put(correlationId, requestResponseFuture);
long cost = System.currentTimeMillis() - beginTimestamp;
this.sendKernelImpl(msg, mq, CommunicationMode.ASYNC, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {View on GitHub (pinned to 293f588571)
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.
Example fix
// before
try { Message r = producer.request(msg, 3000L); }
catch (MQClientException e) { log.error(e.getMessage()); } // 'send request message to <t> fail'
// after
try { Message r = producer.request(msg, 3000L); }
catch (MQClientException e) {
Throwable cause = e.getCause();
if (cause != null && cause.getMessage() != null && cause.getMessage().contains("No route info")) {
topicProvisioner.ensureTopic(msg.getTopic()); // then retry once
} else {
retryQueue.add(msg); // transient send failure: safe to retry (request not delivered)
}
} Defensive patterns
Strategy: try-catch
Validate before calling
// ensure route for the request topic exists before RPC
if (producer.fetchPublishMessageQueues(msg.getTopic()).isEmpty()) {
throw new IllegalStateException("request topic " + msg.getTopic() + " has no route");
} Try / catch
try {
Message reply = producer.request(msg, timeout);
} catch (MQClientException e) { // 'send request message to <t> fail'
Throwable cause = e.getCause();
if (isTransient(cause)) {
producer.request(msg, timeout); // request never landed: retry is safe
} else {
throw new IllegalStateException("request send failed", cause);
}
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- REQUEST_TIMEOUT_EXCEPTION
- send message Exception
- Authorization failed. Please verify your access rights and t
- 13
- Sending message to topic[%s] is forbidden.
AI-assisted analysis of apache/rocketmq@293f588571 (2026-08-14).
Data as JSON: /api/errors/8dad041c2ede8897.
Report an issue: GitHub.