apache/rocketmq · error · MQClientException
subscribe exception
Error message
subscribe exception
What it means
MQClientException thrown by DefaultLitePullConsumerImpl.subscribe (both overloads) as a catch-all wrapper: any exception raised inside the try block while subscribing is rethrown with the generic message 'subscribe exception' and the original as cause. The most common real cause is FilterAPI.buildSubscriptionData rejecting an invalid subscription expression (bad SQL92/tag syntax), but any failure (including the empty-topic IllegalArgumentException) surfaces this way.
Source
Thrown at client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultLitePullConsumerImpl.java:523
setSubscriptionType(SubscriptionType.SUBSCRIBE);
SubscriptionData subscriptionData = FilterAPI.buildSubscriptionData(topic, subExpression);
this.rebalanceImpl.getSubscriptionInner().put(topic, subscriptionData);
this.defaultLitePullConsumer.setMessageQueueListener(new MessageQueueListener() {
@Override
public void messageQueueChanged(String topic, Set<MessageQueue> mqAll, Set<MessageQueue> mqDivided) {
// First, update the assign queue
updateAssignQueueAndStartPullTask(topic, mqAll, mqDivided);
// run custom listener
messageQueueListener.messageQueueChanged(topic, mqAll, mqDivided);
}
});
assignedMessageQueue.setRebalanceImpl(this.rebalanceImpl);
if (serviceState == ServiceState.RUNNING) {
this.mQClientFactory.sendHeartbeatToAllBrokerWithLock();
updateTopicSubscribeInfoWhenSubscriptionChanged();
}
} catch (Exception e) {
throw new MQClientException("subscribe exception", e);
}
}
public synchronized void subscribe(String topic, String subExpression) throws MQClientException {
try {
if (topic == null || "".equals(topic)) {
throw new IllegalArgumentException("Topic can not be null or empty.");
}
setSubscriptionType(SubscriptionType.SUBSCRIBE);
SubscriptionData subscriptionData = FilterAPI.buildSubscriptionData(topic, subExpression);
this.rebalanceImpl.getSubscriptionInner().put(topic, subscriptionData);
this.defaultLitePullConsumer.setMessageQueueListener(new MessageQueueListenerImpl());
assignedMessageQueue.setRebalanceImpl(this.rebalanceImpl);
if (serviceState == ServiceState.RUNNING) {
this.mQClientFactory.sendHeartbeatToAllBrokerWithLock();
updateTopicSubscribeInfoWhenSubscriptionChanged();
}
} catch (Exception e) {View on GitHub (pinned to 293f588571)
Solutions
- Always inspect e.getCause() — it names the actual broken input
- Fix the subscription expression: valid tag syntax like "TAGA || TAGB", or valid SQL92 like "a > 5 AND b IS NOT NULL" with consumer experimental SQL filter enabled where required
- Validate dynamic expressions before passing them to subscribe
- Ensure topic/subExpression are non-null and topic non-empty
Example fix
// before
consumer.subscribe("T", "TAGA || "); // trailing operator -> subscribe exception
// after
try {
consumer.subscribe("T", "TAGA || TAGB");
} catch (MQClientException e) {
throw new IllegalArgumentException("Bad subscription: " + e.getCause().getMessage(), e);
} Defensive patterns
Strategy: try-catch
Validate before calling
// pre-validate a tag expression crudely before subscribing
private boolean looksLikeTagExpr(String expr) {
return expr == null || "*".equals(expr) || expr.matches("[\w ||]+");
}
if (!looksLikeTagExpr(sub)) throw new IllegalArgumentException("bad sub expression: " + sub); Try / catch
try {
consumer.subscribe(topic, subExpression);
} catch (MQClientException e) {
Throwable cause = e.getCause();
if (cause instanceof MQClientException && cause.getMessage().contains("subscription")) {
// invalid expression: fix and resubscribe
} else throw e;
} Prevention
- Unwrap the cause: the generic wrapper hides the real validation error
- Test subscription expressions with FilterAPI.buildSubscriptionData in unit tests before deploying
- Keep tag syntax simple ("TAGA || TAGB") and enable SQL92 support only when used
When it happens
Trigger: subscribe(topic, "TAGA || ") or malformed SQL92 like "a between 1 and" -> buildSubscriptionData throws; empty topic argument; unexpected runtime exceptions during listener wiring. The distinguishing detail lives in e.getCause().
Common situations: Typo'd tag expressions (unbalanced parentheses, bad operators); switching tag filter syntax to SQL92 without enabling sqlFilter support; dynamic expressions built from user input; null subExpression handled differently than expected.
Related errors
- Topic can not be null or empty.
- Authorization failed. Please verify your access rights and t
- add subscription exception
- The consumer not running, please start it first.
- Subscribe and assign are mutually exclusive.
AI-assisted analysis of apache/rocketmq@293f588571 (2026-08-14).
Data as JSON: /api/errors/b2b0190b209b7220.
Report an issue: GitHub.