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

  1. Inspect getCause() of this MQClientException — it holds the real send failure (route missing, broker error, remoting exception).
  2. If cause indicates 'No route info', create/verify the request topic and warm route caches before serving traffic.
  3. 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.
  4. 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

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


AI-assisted analysis of apache/rocketmq@293f588571 (2026-08-14). Data as JSON: /api/errors/8dad041c2ede8897. Report an issue: GitHub.