apache/rocketmq · error · MQClientException

subscription exception

Error message

subscription exception

What it means

Thrown by copySubscription() during start() when building SubscriptionData for any of the registered topics (registerTopics) throws. Each topic is compiled through FilterAPI.buildSubscriptionData(topic, SUB_ALL); any failure — typically a malformed topic name — surfaces wrapped as 'subscription exception'.

Source

Thrown at client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPullConsumerImpl.java:829

        if (this.defaultMQPullConsumer.getConsumerTimeoutMillisWhenSuspend() < this.defaultMQPullConsumer.getBrokerSuspendMaxTimeMillis()) {
            throw new MQClientException(
                "Long polling mode, the consumer consumerTimeoutMillisWhenSuspend must greater than brokerSuspendMaxTimeMillis"
                    + FAQUrl.suggestTodo(FAQUrl.CLIENT_PARAMETER_CHECK_URL),
                null);
        }
    }

    private void copySubscription() throws MQClientException {
        try {
            Set<String> registerTopics = this.defaultMQPullConsumer.getRegisterTopics();
            if (registerTopics != null) {
                for (final String topic : registerTopics) {
                    SubscriptionData subscriptionData = FilterAPI.buildSubscriptionData(topic, SubscriptionData.SUB_ALL);
                    this.rebalanceImpl.getSubscriptionInner().put(topic, subscriptionData);
                }
            }
        } catch (Exception e) {
            throw new MQClientException("subscription exception", e);
        }
    }

    public void updateConsumeOffset(MessageQueue mq, long offset) throws MQClientException {
        this.isRunning();
        this.offsetStore.updateOffset(mq, offset, false);
    }

    public MessageExt viewMessage(String topic, String msgId)
        throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
        this.isRunning();
        return this.mQClientFactory.getMQAdminImpl().viewMessage(topic, msgId);
    }

    public void registerFilterMessageHook(final FilterMessageHook hook) {
        this.filterMessageHookList.add(hook);
        log.info("register FilterMessageHook Hook, {}", hook.hookName());
    }

View on GitHub (pinned to 293f588571)

Solutions

  1. Inspect the cause chain — the wrapped exception names the offending topic and reason
  2. Sanitize/validate topic names against Validators.topicValidator (regex ^[%|a-zA-Z0-9_-]+$) before registering them
  3. Trim whitespace from topic strings sourced from config files or env vars

Example fix

// before
consumer.setRegisterTopics(Sets.newHashSet("order topic", "")); // invalid
consumer.start();

// after
Set<String> topics = rawTopics.stream()
    .map(String::trim)
    .filter(t -> t.matches("[%|a-zA-Z0-9_-]+"))
    .collect(Collectors.toSet());
consumer.setRegisterTopics(topics);
consumer.start();
Defensive patterns

Strategy: validation

Validate before calling

for (String t : topics) {
    if (!t.trim().matches("[%|a-zA-Z0-9_-]+") || t.length() > 127)
        throw new IllegalArgumentException("invalid topic: " + t);
}

Try / catch

catch (MQClientException e) { log.error("subscription failed, cause:", e.getCause()); }

Prevention

When it happens

Trigger: Calling setRegisterTopics(...) with a topic containing illegal characters or violating length limits before start(); a topic string with whitespace, empty string, or characters FilterAPI's TopicFilter rejects (valid pattern is ^[%|a-zA-Z0-9_-]+$ with length <= 127 in Validators).

Common situations: Topic names constructed from user input or environment variables without validation; trailing whitespace or newline in topic strings read from config files; topics exceeding the 127-char limit after concatenating prefixes.

Related errors


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