apache/rocketmq · error · MQClientException

message's topic not equal mq's topic

Error message

message's topic not equal mq's topic

What it means

MQClientException thrown by send(Message, MessageQueue) variants when msg.getTopic() does not String.equals the target MessageQueue's topic. Sending to an explicit queue requires the message and queue to belong to the same topic - the client will not route a message of topic A into a queue of topic B. Checked after makeSureStateOK and Validators.checkMessage, before any timeout accounting or network call.

Source

Thrown at client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java:1235

        }
    }

    /**
     * KERNEL SYNC -------------------------------------------------------
     */
    public SendResult send(Message msg, MessageQueue mq)
        throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
        return send(msg, mq, this.defaultMQProducer.getSendMsgTimeout());
    }

    public SendResult send(Message msg, MessageQueue mq, long timeout)
        throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
        long beginStartTime = System.currentTimeMillis();
        this.makeSureStateOK();
        Validators.checkMessage(msg, this.defaultMQProducer);

        if (!msg.getTopic().equals(mq.getTopic())) {
            throw new MQClientException("message's topic not equal mq's topic", null);
        }

        long costTime = System.currentTimeMillis() - beginStartTime;
        if (timeout < costTime) {
            throw new RemotingTooMuchRequestException("call timeout");
        }

        return this.sendKernelImpl(msg, mq, CommunicationMode.SYNC, null, null, timeout);
    }

    /**
     * KERNEL ASYNC -------------------------------------------------------
     */
    public void send(Message msg, MessageQueue mq, SendCallback sendCallback)
        throws MQClientException, RemotingException, InterruptedException {
        send(msg, mq, sendCallback, this.defaultMQProducer.getSendMsgTimeout());
    }

View on GitHub (pinned to 293f588571)

Solutions

  1. Derive the queue and the message from the same topic constant: new Message(TOPIC, ...) and queues from fetchPublishMessageQueues(TOPIC)
  2. If namespaces are in play, align both sides: build the message topic with the namespace, or strip it from both before comparing; log both values on failure
  3. Add an assertion/utility before send: Objects.equals(msg.getTopic(), mq.getTopic()) with a clear error including both strings
  4. Re-fetch queues when the producer's topic/namespace config changes instead of caching stale MessageQueue objects

Example fix

// before
Message msg = new Message("ORDER_TOPIC", body);
MessageQueue mq = userQueues.get(0); // queue of PAYMENT_TOPIC
producer.send(msg, mq);
// after
Message msg = new Message(ORDER_TOPIC, body);
List<MessageQueue> mqs = producer.fetchPublishMessageQueues(ORDER_TOPIC);
producer.send(msg, mqs.get(0));
Defensive patterns

Strategy: validation

Validate before calling

 public SendResult sendTo(Message msg, MessageQueue mq) throws Exception {
    if (!Objects.equals(msg.getTopic(), mq.getTopic())) {
        throw new IllegalArgumentException(
            "topic mismatch: message=" + msg.getTopic() + " queue=" + mq.getTopic());
    }
    return producer.send(msg, mq);
}

Type guard

 boolean isQueueForTopic(MessageQueue mq, String topic) {
    return mq != null && Objects.equals(mq.getTopic(), topic);
}

Try / catch

try {
    producer.send(msg, mq);
} catch (MQClientException e) {
    if ("message's topic not equal mq's topic".equals(e.getMessage())) {
        throw new IllegalArgumentException("Queue " + mq + " not usable for topic " + msg.getTopic(), e);
    }
    throw e;
}

Prevention

When it happens

Trigger: triggerScenarios

Common situations: commonSituations

Related errors


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