apache/rocketmq · error · MQClientException

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

Error message

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

What it means

start() switches on serviceState; if it is already RUNNING, START_FAILED, or SHUTDOWN_ALREADY, it refuses to start again and throws this exception with the CLIENT_SERVICE_NOT_OK FAQ hint. A DefaultMQPushConsumer is a single-use object: it cannot be started twice or restarted after shutdown.

Source

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

                this.consumeMessagePopService.start();

                boolean registerOK = mQClientFactory.registerConsumer(this.defaultMQPushConsumer.getConsumerGroup(), this);
                if (!registerOK) {
                    this.serviceState = ServiceState.CREATE_JUST;
                    this.consumeMessageService.shutdown(defaultMQPushConsumer.getAwaitTerminationMillisWhenShutdown());
                    throw new MQClientException("The consumer group[" + this.defaultMQPushConsumer.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.defaultMQPushConsumer.getConsumerGroup());
                this.serviceState = ServiceState.RUNNING;
                break;
            case RUNNING:
            case START_FAILED:
            case SHUTDOWN_ALREADY:
                throw new MQClientException("The PushConsumer service state not OK, maybe started once, "
                    + this.serviceState
                    + FAQUrl.suggestTodo(FAQUrl.CLIENT_SERVICE_NOT_OK),
                    null);
            default:
                break;
        }

        try {
            this.updateTopicSubscribeInfoWhenSubscriptionChanged();
            this.mQClientFactory.checkClientInBroker();
            if (this.mQClientFactory.sendHeartbeatToAllBrokerWithLock()) {
                this.mQClientFactory.rebalanceImmediately();
            }
        } catch (Exception e) {
            log.warn("Start the consumer {} fail.", this.defaultMQPushConsumer.getConsumerGroup(), e);
            shutdown();
            throw e;
        }

View on GitHub (pinned to 293f588571)

Solutions

  1. Construct a fresh DefaultMQPushConsumer instance for each start attempt instead of reusing one
  2. Fix the root cause of the first failed start() (often error 223, duplicate group) — the state error is secondary
  3. Guard start() with your own boolean or check consumer.getDefaultMQPushConsumerImpl().getServiceState() before calling
  4. In Spring, let the container manage lifecycle (start once in afterPropertiesSet/@PostConstruct, shutdown in destroy)

Example fix

// before
try { consumer.start(); } catch (Exception e) { consumer.start(); } // second call -> state not OK

// after
try {
    consumer.start();
} catch (Exception e) {
    consumer.shutdown();
    consumer = buildConsumer(); // fresh instance, re-subscribe, then start
    consumer.start();
}
Defensive patterns

Strategy: validation

Validate before calling

// guard against double start in your wrapper
private final AtomicBoolean started = new AtomicBoolean(false);
public void start() throws MQClientException {
    if (!started.compareAndSet(false, true)) return; // idempotent
    consumer.start();
}

Try / catch

try {
    consumer.start();
} catch (MQClientException e) {
    if (e.getMessage().contains("maybe started once")) {
        // wrong lifecycle usage: build a NEW consumer instead of retrying
        throw new IllegalStateException("Consumer reused; create a new instance", e);
    } else throw e;
}

Prevention

When it happens

Trigger: Calling consumer.start() a second time on the same instance; calling start() after a previous start() threw (state stuck at START_FAILED); calling start() on an instance that was shutdown().

Common situations: Retry logic in application code that blindly re-invokes start() after a failure; Spring @PostConstruct plus manual start(); restart-on-failure loops that reuse the same consumer object instead of constructing a new one.

Related errors


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