apache/rocketmq · error · MQClientException
subscription is null
Error message
subscription is null
What it means
checkConfig() requires the subscription map to be non-null. subscribe() populates it, so this fires when start() is called before any subscribe() — the consumer has nothing to consume and the client refuses to start with a null subscription table.
Source
Thrown at client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java:1076
Date dt = UtilAll.parseDate(this.defaultMQPushConsumer.getConsumeTimestamp(), UtilAll.YYYYMMDDHHMMSS);
if (null == dt) {
throw new MQClientException(
"consumeTimestamp is invalid, the valid format is yyyyMMddHHmmss,but received "
+ this.defaultMQPushConsumer.getConsumeTimestamp()
+ " " + FAQUrl.suggestTodo(FAQUrl.CLIENT_PARAMETER_CHECK_URL), null);
}
// allocateMessageQueueStrategy
if (null == this.defaultMQPushConsumer.getAllocateMessageQueueStrategy()) {
throw new MQClientException(
"allocateMessageQueueStrategy is null"
+ FAQUrl.suggestTodo(FAQUrl.CLIENT_PARAMETER_CHECK_URL),
null);
}
// subscription
if (null == this.defaultMQPushConsumer.getSubscription()) {
throw new MQClientException(
"subscription is null"
+ FAQUrl.suggestTodo(FAQUrl.CLIENT_PARAMETER_CHECK_URL),
null);
}
// messageListener
if (null == this.defaultMQPushConsumer.getMessageListener()) {
throw new MQClientException(
"messageListener is null"
+ FAQUrl.suggestTodo(FAQUrl.CLIENT_PARAMETER_CHECK_URL),
null);
}
boolean orderly = this.defaultMQPushConsumer.getMessageListener() instanceof MessageListenerOrderly;
boolean concurrently = this.defaultMQPushConsumer.getMessageListener() instanceof MessageListenerConcurrently;
if (!orderly && !concurrently) {
throw new MQClientException(
"messageListener must be instanceof MessageListenerOrderly or MessageListenerConcurrently"View on GitHub (pinned to 293f588571)
Solutions
- Call consumer.subscribe(topic, "*") (or an SQL92/tag expression) before start()
- If topics come from a list, fail loudly when the list is empty instead of starting with nothing
- Keep subscribe-before-start ordering in your consumer factory method
Example fix
// before
DefaultMQPushConsumer c = new DefaultMQPushConsumer("g");
c.setMessageListener(...);
c.start(); // no subscribe() -> subscription is null
// after
c.subscribe("order-topic", "*");
c.setMessageListener(...);
c.start(); Defensive patterns
Strategy: validation
Validate before calling
if (topics == null || topics.isEmpty())
throw new IllegalArgumentException("At least one topic required");
for (String t : topics) consumer.subscribe(t, "*");
consumer.start(); Prevention
- Always subscribe before start in one factory method
- Fail config load when the topic list is empty rather than starting a no-op consumer
When it happens
Trigger: Calling consumer.start() without ever calling consumer.subscribe(topic, subExpression); code that clears subscriptions (getSubscription().clear()) before start; conditional subscription logic that skips all subscribe calls on some path.
Common situations: Forgetting subscribe() in quick-start code; per-environment wiring where the topic list is empty in one environment so the subscribe loop never runs.
Related errors
- lite subscription quota exceeded
- consumerGroup can not equal
- subscription exception
- consumerGroup is null
- messageModel is null
AI-assisted analysis of apache/rocketmq@293f588571 (2026-08-14).
Data as JSON: /api/errors/278dfea34b053553.
Report an issue: GitHub.