apache/rocketmq · error · MQClientException

messageListener must be instanceof MessageListenerOrderly or

Error message

messageListener must be instanceof MessageListenerOrderly or MessageListenerConcurrently

What it means

checkConfig() accepts only MessageListenerOrderly or MessageListenerConcurrently as the listener type (checked via instanceof after the null check). Any other MessageListener implementation (the base interface has others, e.g. MessageListenerOrderly/Concurrently are the supported concrete contracts) is rejected because the push consumer's dispatch machinery only implements these two protocols.

Source

Thrown at client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java:1093

        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"
                    + FAQUrl.suggestTodo(FAQUrl.CLIENT_PARAMETER_CHECK_URL),
                null);
        }

        // consumeThreadMin
        if (this.defaultMQPushConsumer.getConsumeThreadMin() < 1
            || this.defaultMQPushConsumer.getConsumeThreadMin() > 1000) {
            throw new MQClientException(
                "consumeThreadMin Out of range [1, 1000]"
                    + FAQUrl.suggestTodo(FAQUrl.CLIENT_PARAMETER_CHECK_URL),
                null);
        }

        // consumeThreadMax
        if (this.defaultMQPushConsumer.getConsumeThreadMax() < 1 || this.defaultMQPushConsumer.getConsumeThreadMax() > 1000) {
            throw new MQClientException(
                "consumeThreadMax Out of range [1, 1000]"

View on GitHub (pinned to 293f588571)

Solutions

  1. Implement MessageListenerConcurrently (default choice) or MessageListenerOrderly (for ordered consumption with queue-level locking)
  2. If you wrote a custom interface, wrap it in an adapter class implementing one of the two supported listeners
  3. Use the exact lambdas: (MessageListenerConcurrently) or (MessageListenerOrderly) casts so the compiler targets the right interface

Example fix

// before
class MyListener implements MessageListener { ... } // base interface only
c.registerMessageListener(new MyListener()); // rejected

// after
class MyListener implements MessageListenerConcurrently {
    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext ctx) { ... return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; }
}
c.registerMessageListener(new MyListener());
Defensive patterns

Strategy: type-guard

Validate before calling

Objects.requireNonNull(listener, "listener required");
if (!(listener instanceof MessageListenerConcurrently) && !(listener instanceof MessageListenerOrderly))
    throw new IllegalArgumentException("Listener must be MessageListenerConcurrently or MessageListenerOrderly");
consumer.registerMessageListener(listener);

Type guard

boolean isSupportedListener(MessageListener l) {
    return l instanceof MessageListenerConcurrently || l instanceof MessageListenerOrderly;
}

Prevention

When it happens

Trigger: Passing a listener that implements only the base org.apache.rocketmq.client.consumer.listener.MessageListener interface; passing a custom subinterface; passing a lambdas targeted at an unsupported functional interface.

Common situations: Implementing the generic interface 'to be flexible'; upgrading from old client versions where listener handling differed; mocking MessageListener in tests.

Related errors


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