apache/rocketmq · error · MQClientException

The consumer service state not OK, {serviceState}

Error message

The consumer service state not OK, {serviceState}

What it means

makeSureStateOK() is called before state-sensitive consumer operations (e.g. pull/pop message paths) and throws unless the consumer's serviceState is RUNNING. It protects internal APIs from being used on a consumer that has not completed start() or has already been shutdown().

Source

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

            }

            if (msgFoundList.size() != msgListFilterAgain.size()) {
                for (MessageExt msg : msgFoundList) {
                    if (!msgListFilterAgain.contains(msg)) {
                        ackAsync(msg, this.groupName());
                    }
                }
            }

            popResult.setMsgFoundList(msgListFilterAgain);
        }

        return popResult;
    }

    private void makeSureStateOK() throws MQClientException {
        if (this.serviceState != ServiceState.RUNNING) {
            throw new MQClientException("The consumer service state not OK, "
                + this.serviceState
                + FAQUrl.suggestTodo(FAQUrl.CLIENT_SERVICE_NOT_OK),
                null);
        }
    }

    void executePullRequestLater(final PullRequest pullRequest, final long timeDelay) {
        this.mQClientFactory.getPullMessageService().executePullRequestLater(pullRequest, timeDelay);
    }

    public boolean isPause() {
        return pause;
    }

    public void setPause(boolean pause) {
        this.pause = pause;
    }

View on GitHub (pinned to 293f588571)

Solutions

  1. Ensure consumer.start() completes before any message operations; check for exceptions from start()
  2. Do not reuse a DefaultMQPushConsumer after shutdown(); create a fresh instance instead
  3. If start() previously failed, inspect the earlier exception — this state error is only a symptom
  4. Delay shutdown until all in-flight consumer API calls have drained (e.g. during graceful application stop)

Example fix

// before
DefaultMQPushConsumer c = new DefaultMQPushConsumer("g");
c.subscribe("t", "*");
c.shutdown();
c.fetchSubscribeMessageQueues("t"); // state is SHUTDOWN_ALREADY

// after
DefaultMQPushConsumer c = new DefaultMQPushConsumer("g");
c.subscribe("t", "*");
c.start();
try {
    c.fetchSubscribeMessageQueues("t");
} finally {
    c.shutdown();
}
// any later need: construct a new consumer instance
Defensive patterns

Strategy: try-catch

Validate before calling

// guard state before calling state-sensitive APIs
import org.apache.rocketmq.client.impl.consumer.DefaultMQPushConsumerImpl; // internal: prefer tracking lifecycle in your own wrapper
if (!started.get()) throw new IllegalStateException("consumer not started");

Try / catch

try {
    consumer.fetchSubscribeMessageQueues(topic);
} catch (MQClientException e) {
    if (e.getMessage().contains("service state not OK")) {
        // consumer is stopped/failed: reinitialize or skip, do not blindly retry
        reinitConsumer();
    } else throw e;
}

Prevention

When it happens

Trigger: Invoking message-population APIs (such as popMessage-related paths guarded by makeSureStateOK) before consumer.start() finished, after consumer.shutdown(), or while start() failed midway and left the state as CREATE_JUST/START_FAILED.

Common situations: Reusing a consumer instance after shutdown(); calling consumer methods from a thread before start() returned; a previous start() failure (e.g. duplicate consumer group) left the object in a non-RUNNING state; calling shutdown() during application undeploy and then issuing requests.

Related errors


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