apache/rocketmq · error · IllegalArgumentException
Message queues can not be null or empty.
Error message
Message queues can not be null or empty.
What it means
DefaultLitePullConsumerImpl.assign(Collection<MessageQueue>) throws this IllegalArgumentException when the passed collection is null or empty. In ASSIGN mode the consumer pulls exclusively from the queues you explicitly assign, so an empty assignment leaves it nothing to consume and is rejected outright.
Source
Thrown at client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultLitePullConsumerImpl.java:578
assignedMessageQueue.setRebalanceImpl(this.rebalanceImpl);
if (serviceState == ServiceState.RUNNING) {
this.mQClientFactory.sendHeartbeatToAllBrokerWithLock();
updateTopicSubscribeInfoWhenSubscriptionChanged();
}
} catch (Exception e) {
throw new MQClientException("subscribe exception", e);
}
}
public synchronized void unsubscribe(final String topic) {
this.rebalanceImpl.getSubscriptionInner().remove(topic);
removePullTaskCallback(topic);
assignedMessageQueue.removeAssignedMessageQueue(topic);
}
public synchronized void assign(Collection<MessageQueue> messageQueues) {
if (messageQueues == null || messageQueues.isEmpty()) {
throw new IllegalArgumentException("Message queues can not be null or empty.");
}
setSubscriptionType(SubscriptionType.ASSIGN);
assignedMessageQueue.updateAssignedMessageQueue(messageQueues);
if (serviceState == ServiceState.RUNNING) {
updateAssignPullTask(messageQueues);
}
}
public synchronized void setSubExpressionForAssign(final String topic, final String subExpression) {
if (StringUtils.isBlank(subExpression)) {
throw new IllegalArgumentException("subExpression can not be null or empty.");
}
if (serviceState != ServiceState.CREATE_JUST) {
throw new IllegalStateException("setAssignTag only can be called before start.");
}
setSubscriptionType(SubscriptionType.ASSIGN);
topicToSubExpression.put(topic, subExpression);
}View on GitHub (pinned to 293f588571)
Solutions
- Guard: only call assign when the collection is non-null and !isEmpty()
- If the list came from fetchMessageQueues, wait/retry until topic route metadata returns queues
- Fall back to subscribe() mode if dynamic queue discovery is what you actually need
Example fix
// before
consumer.assign(queues.stream().filter(q -> q.getBrokerName().equals(broker)).collect(Collectors.toList()));
// after
List<MessageQueue> selected = queues.stream().filter(q -> q.getBrokerName().equals(broker)).collect(Collectors.toList());
if (!selected.isEmpty()) consumer.assign(selected); else throw new IllegalStateException("no queues for broker " + broker); Defensive patterns
Strategy: validation
Validate before calling
if (messageQueues != null && !messageQueues.isEmpty()) {
consumer.assign(messageQueues);
} else {
throw new IllegalStateException("queue list empty — check topic route metadata");
} Prevention
- Never pass a filtered collection straight to assign() — check size first
- If queues come from fetchMessageQueues, handle the empty result explicitly
When it happens
Trigger: consumer.assign(null) or consumer.assign(Collections.emptyList()) on a DefaultLitePullConsumer; assigning a queue list filtered down to zero entries.
Common situations: Queue lists fetched from fetchMessageQueues(topic) then filtered by tags/fields until empty; race where the topic metadata returns no queues yet and assign is called with the empty result.
Related errors
- subExpression can not be null or empty.
- The message queue is not in assigned list, message queue:
- consumerGroup can not equal
- Topic can not be null or empty.
- Timeout must not be negative
AI-assisted analysis of apache/rocketmq@293f588571 (2026-08-14).
Data as JSON: /api/errors/1efd225ba78de362.
Report an issue: GitHub.