{"record":{"id":"f7f4b5bde3577f53","repo":"apache/rocketmq","slug":"the-producer-service-state-not-ok-maybe-started-o","errorCode":null,"errorMessage":"The producer service state not OK, maybe started once, {serviceState}","messagePattern":"The producer 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/producer/DefaultMQProducerImpl.java","lineNumber":281,"sourceCode":"                        null);\n                }\n\n                if (startFactory) {\n                    mQClientFactory.start();\n                }\n\n                this.initTopicRoute();\n\n                this.mqFaultStrategy.startDetector();\n\n                log.info(\"the producer [{}] start OK. sendMessageWithVIPChannel={}\", this.defaultMQProducer.getProducerGroup(),\n                    this.defaultMQProducer.isSendMessageWithVIPChannel());\n                this.serviceState = ServiceState.RUNNING;\n                break;\n            case RUNNING:\n            case START_FAILED:\n            case SHUTDOWN_ALREADY:\n                throw new MQClientException(\"The producer 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        this.mQClientFactory.sendHeartbeatToAllBrokerWithLock();\n\n        RequestFutureHolder.getInstance().startScheduledTask(this);\n\n    }\n\n    private void checkConfig() throws MQClientException {\n        Validators.checkGroup(this.defaultMQProducer.getProducerGroup());\n\n        if (this.defaultMQProducer.getProducerGroup().equals(MixAll.DEFAULT_PRODUCER_GROUP)) {\n            throw new MQClientException(\"producerGroup can not equal \" + MixAll.DEFAULT_PRODUCER_GROUP + \", please specify another one.\",","sourceCodeStart":263,"sourceCodeEnd":299,"githubUrl":"https://github.com/apache/rocketmq/blob/293f5885719fc4aa3619446a1900f58ccfcfdd29/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java#L263-L299","documentation":"MQClientException thrown from DefaultMQProducerImpl.start() when the service state is anything other than CREATE_JUST at switch entry - i.e. RUNNING (already started), START_FAILED, or SHUTDOWN_ALREADY. The producer is a one-shot state machine: CREATE_JUST -> RUNNING -> SHUTDOWN_ALREADY, and start() is only legal in the initial state. The message includes the offending state so you can tell which case you hit.","triggerScenarios":"Calling producer.start() twice without shutdown() in between; calling start() on a producer whose previous start() failed midway (state left as START_FAILED); calling start() after shutdown() (state SHUTDOWN_ALREADY is terminal).","commonSituations":"commonSituations","solutions":["Audit call sites and guarantee start() runs exactly once per producer instance (guard with a started flag or use Spring lifecycle single-start)","If the previous start failed, discard the instance and build a fresh DefaultMQProducer (state START_FAILED cannot be recovered)","If you need to restart after shutdown(), create a new producer object; SHUTDOWN_ALREADY is terminal","Catch this specific MQClientException in wrappers and treat it as 'already running' (idempotent start) rather than propagating"],"exampleFix":"// before\npublic void ensureStarted() { producer.start(); } // throws on 2nd call\n// after\nprivate final AtomicBoolean started = new AtomicBoolean();\npublic void ensureStarted() throws MQClientException {\n    if (started.compareAndSet(false, true)) producer.start();\n}","handlingStrategy":"validation","validationCode":" private final AtomicBoolean started = new AtomicBoolean();\npublic void start() throws MQClientException {\n    if (started.compareAndSet(false, true)) {\n        producer.start();\n    } // else: already started, no-op\n}","typeGuard":null,"tryCatchPattern":"try {\n    producer.start();\n} catch (MQClientException e) {\n    String state = e.getMessage(); // message embeds RUNNING / SHUTDOWN_ALREADY / START_FAILED\n    if (state.contains(\"RUNNING\")) { /* idempotent start - ignore */ }\n    else if (state.contains(\"SHUTDOWN_ALREADY\") || state.contains(\"START_FAILED\")) {\n        producer = newProducer(); producer.start(); // fresh instance\n    } else throw e;\n}","preventionTips":["Make start() idempotent in wrapper code with an AtomicBoolean/Lock guard","Never reuse a producer after shutdown() - build a new instance","Keep send-retry logic from re-invoking start(); only send() needs retrying","Centralize producer lifecycle in one component instead of scattering start() calls"],"tags":["rocketmq","producer","lifecycle","state-machine"],"backgroundTag":null,"analyzedSha":"293f5885719fc4aa3619446a1900f58ccfcfdd29","analyzedAt":"2026-08-14T11:50:13.822Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}