{"record":{"id":"f1a23a834dac7e53","repo":"apache/rocketmq","slug":"the-pushconsumer-service-state-not-ok-maybe-start","errorCode":null,"errorMessage":"The PushConsumer service state not OK, maybe started once, {serviceState}","messagePattern":"The PushConsumer service state not OK, maybe started once, (.+?)","errorType":"exception","errorClass":"MQClientException","httpStatus":null,"severity":"error","filePath":"client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java","lineNumber":1004,"sourceCode":"                this.consumeMessagePopService.start();\n\n                boolean registerOK = mQClientFactory.registerConsumer(this.defaultMQPushConsumer.getConsumerGroup(), this);\n                if (!registerOK) {\n                    this.serviceState = ServiceState.CREATE_JUST;\n                    this.consumeMessageService.shutdown(defaultMQPushConsumer.getAwaitTerminationMillisWhenShutdown());\n                    throw new MQClientException(\"The consumer group[\" + this.defaultMQPushConsumer.getConsumerGroup()\n                        + \"] has been created before, specify another name please.\" + FAQUrl.suggestTodo(FAQUrl.GROUP_NAME_DUPLICATE_URL),\n                        null);\n                }\n\n                mQClientFactory.start();\n                log.info(\"the consumer [{}] start OK.\", this.defaultMQPushConsumer.getConsumerGroup());\n                this.serviceState = ServiceState.RUNNING;\n                break;\n            case RUNNING:\n            case START_FAILED:\n            case SHUTDOWN_ALREADY:\n                throw new MQClientException(\"The PushConsumer service state not OK, maybe started once, \"\n                    + this.serviceState\n                    + FAQUrl.suggestTodo(FAQUrl.CLIENT_SERVICE_NOT_OK),\n                    null);\n            default:\n                break;\n        }\n\n        try {\n            this.updateTopicSubscribeInfoWhenSubscriptionChanged();\n            this.mQClientFactory.checkClientInBroker();\n            if (this.mQClientFactory.sendHeartbeatToAllBrokerWithLock()) {\n                this.mQClientFactory.rebalanceImmediately();\n            }\n        } catch (Exception e) {\n            log.warn(\"Start the consumer {} fail.\", this.defaultMQPushConsumer.getConsumerGroup(), e);\n            shutdown();\n            throw e;\n        }","sourceCodeStart":986,"sourceCodeEnd":1022,"githubUrl":"https://github.com/apache/rocketmq/blob/293f5885719fc4aa3619446a1900f58ccfcfdd29/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java#L986-L1022","documentation":"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.","triggerScenarios":"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().","commonSituations":"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.","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)"],"exampleFix":"// before\ntry { consumer.start(); } catch (Exception e) { consumer.start(); } // second call -> state not OK\n\n// after\ntry {\n    consumer.start();\n} catch (Exception e) {\n    consumer.shutdown();\n    consumer = buildConsumer(); // fresh instance, re-subscribe, then start\n    consumer.start();\n}","handlingStrategy":"validation","validationCode":"// guard against double start in your wrapper\nprivate final AtomicBoolean started = new AtomicBoolean(false);\npublic void start() throws MQClientException {\n    if (!started.compareAndSet(false, true)) return; // idempotent\n    consumer.start();\n}","typeGuard":null,"tryCatchPattern":"try {\n    consumer.start();\n} catch (MQClientException e) {\n    if (e.getMessage().contains(\"maybe started once\")) {\n        // wrong lifecycle usage: build a NEW consumer instead of retrying\n        throw new IllegalStateException(\"Consumer reused; create a new instance\", e);\n    } else throw e;\n}","preventionTips":["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"],"tags":["rocketmq","lifecycle","consumer-state","double-start"],"backgroundTag":null,"analyzedSha":"293f5885719fc4aa3619446a1900f58ccfcfdd29","analyzedAt":"2026-08-14T11:50:13.822Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}