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
- Construct a fresh DefaultMQPushConsumer instance for each start attempt instead of reusing one
- Fix the root cause of the first failed start() (often error 223, duplicate group) — the state error is secondary
- Guard start() with your own boolean or check consumer.getDefaultMQPushConsumerImpl().getServiceState() before calling
- 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
- Treat DefaultMQPushConsumer as single-use: one start() per instance
- Wrap it in a lifecycle-managed component that forbids double start
- On start failure, always shutdown() and rebuild a fresh instance for the retry
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
- The consumer service state not OK, {serviceState}
- The consumer not running, please start it first.
- Subscribe and assign are mutually exclusive.
- The PullConsumer service state not OK, maybe started once,
- setAssignTag only can be called before start.
AI-assisted analysis of apache/rocketmq@293f588571 (2026-08-14).
Data as JSON: /api/errors/f1a23a834dac7e53.
Report an issue: GitHub.