apache/rocketmq · error · MQClientException

The PullConsumer service state not OK, maybe started once, {

Error message

The PullConsumer service state not OK, maybe started once, {serviceState}

What it means

Thrown by DefaultMQPullConsumerImpl.start() when the service state is anything other than CREATE_JUST — specifically RUNNING, START_FAILED, or SHUTDOWN_ALREADY. The consumer is a one-shot state machine: start() may only transition CREATE_JUST -> RUNNING; calling start() twice or after shutdown()/a failed start is rejected.

Source

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

                this.offsetStore.load();

                boolean registerOK = mQClientFactory.registerConsumer(this.defaultMQPullConsumer.getConsumerGroup(), this);
                if (!registerOK) {
                    this.serviceState = ServiceState.CREATE_JUST;

                    throw new MQClientException("The consumer group[" + this.defaultMQPullConsumer.getConsumerGroup()
                        + "] has been created before, specify another name please." + FAQUrl.suggestTodo(FAQUrl.GROUP_NAME_DUPLICATE_URL),
                        null);
                }

                mQClientFactory.start();
                log.info("the consumer [{}] start OK", this.defaultMQPullConsumer.getConsumerGroup());
                this.serviceState = ServiceState.RUNNING;
                break;
            case RUNNING:
            case START_FAILED:
            case SHUTDOWN_ALREADY:
                throw new MQClientException("The PullConsumer service state not OK, maybe started once, "
                    + this.serviceState
                    + FAQUrl.suggestTodo(FAQUrl.CLIENT_SERVICE_NOT_OK),
                    null);
            default:
                break;
        }

    }

    private void checkConfig() throws MQClientException {
        // check consumerGroup
        Validators.checkGroup(this.defaultMQPullConsumer.getConsumerGroup());

        // consumerGroup
        if (null == this.defaultMQPullConsumer.getConsumerGroup()) {
            throw new MQClientException(
                "consumerGroup is null"
                    + FAQUrl.suggestTodo(FAQUrl.CLIENT_PARAMETER_CHECK_URL),

View on GitHub (pinned to 293f588571)

Solutions

  1. Create a new DefaultMQPullConsumer instance after shutdown() instead of restarting the same one
  2. Ensure start() is called exactly once, guarded by your own lifecycle flag or a framework @PostConstruct single invocation
  3. If a previous start() failed, log the original cause (state will be START_FAILED) and rebuild the consumer with corrected config

Example fix

// before
consumer.shutdown();
consumer.start(); // SHUTDOWN_ALREADY -> throws

// after
consumer.shutdown();
consumer = new DefaultMQPullConsumer(group);
consumer.setNamesrvAddr(namesrv);
consumer.start();
Defensive patterns

Strategy: validation

Validate before calling

// guard start with your own flag
if (started.compareAndSet(false, true)) consumer.start();

Prevention

When it happens

Trigger: Calling consumer.start() a second time after it already succeeded (state RUNNING); calling start() again after a previous start() threw (state START_FAILED); calling start() after shutdown() (state SHUTDOWN_ALREADY).

Common situations: Reconnect logic that blindly calls start() on every connection loss; lifecycle code where start() is invoked from multiple threads; frameworks re-initializing beans without recreating the consumer object.

Related errors


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