apache/rocketmq · error · MQClientException
The Factory object[{clientId}] has been created before, and
Error message
The Factory object[{clientId}] has been created before, and failed. What it means
Thrown by MQClientInstance.start() when start() is called on a client-instance whose previous start attempt already failed (state START_FAILED). Each clientId maps to one shared MQClientInstance; a failed start leaves the instance registered but unusable, so any subsequent producer/consumer sharing that clientId gets this exception instead of a retry. A failed instance must be fully shut down (removed from the manager) before a fresh start can succeed.
Source
Thrown at client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java:371
// Start pull service
this.pullMessageService.start();
// Start rebalance service
this.rebalanceService.start();
// Start push service
this.defaultMQProducer.getDefaultMQProducerImpl().start(false);
log.info("the client factory [{}] start OK", this.clientId);
this.serviceState = ServiceState.RUNNING;
} catch (MQClientException | RuntimeException | Error e) {
// Do not apply the normal shutdown registration guards here: a factory that never reached
// RUNNING cannot serve any registered client, and its partially started resources must stop.
// Existing holders still observe START_FAILED; a later manager lookup may create a replacement.
cleanupAfterStartFailure(e);
MQClientManager.getInstance().removeClientFactory(this.clientId, this);
throw e;
}
break;
case START_FAILED:
throw new MQClientException("The Factory object[" + this.getClientId() + "] has been created before, and failed.", null);
default:
break;
}
}
}
private void cleanupAfterStartFailure(Throwable cause) {
runCleanup(this.scheduledExecutorService::shutdownNow, cause);
if (this.concurrentHeartbeatExecutor != null) {
runCleanup(this.concurrentHeartbeatExecutor::shutdownNow, cause);
}
runCleanup(() -> this.defaultMQProducer.getDefaultMQProducerImpl().shutdown(false), cause);
runCleanup(() -> this.pullMessageService.shutdown(true), cause);
runCleanup(this.rebalanceService::shutdown, cause);
runCleanup(this.mQClientAPIImpl::shutdown, cause);
}
private void startScheduledTask() {View on GitHub (pinned to 293f588571)
Solutions
- On start failure, fully release the failed instance before retrying: call shutdown() on the consumer/producer whose start failed (post-patch, the factory itself cleans up and deregisters from MQClientManager), then create a fresh consumer/producer object
- Give every client a unique instanceName (setInstanceName) so a failed instance cannot poison another client sharing the same clientId
- Do not call start() twice on the same object after a failure — create a new instance instead
- Fix the root cause of the first failure (NameServer address, ACL) before attempting restart
Example fix
// before
try { consumer.start(); } catch (Exception e) { /* ignored */ }
consumer.start(); // -> The Factory object[...] has been created before, and failed.
// after
try { consumer.start(); }
catch (MQClientException e) {
consumer.shutdown(); // release the failed instance
consumer = buildConsumer(); // fresh object, unique instanceName
consumer.start();
} Defensive patterns
Strategy: fallback
Validate before calling
// before any restart attempt, ensure the previous failed instance was released
// (post-cleanup builds deregister from MQClientManager automatically)
if (previousConsumer != null && previousConsumer.getDefaultMQPushConsumerImpl() != null) previousConsumer.shutdown();
// and keep instanceName unique per client
consumer.setInstanceName("order-consumer-" + UUID.randomUUID()); Try / catch
try { consumer.start(); } catch (MQClientException e) {
if (e.getMessage().contains("has been created before, and failed")) {
consumer.shutdown(); // release poisoned instance
consumer = buildNewConsumer(); // fresh object, unique instanceName
consumer.start();
} else throw e;
} Prevention
- Never call start() twice on a client whose start failed — build a new one
- Set a unique instanceName per consumer/producer to avoid clientId collisions
- Fix root-cause start failures (namesrvAddr, ACL) before restart loops
- Frameworks restarting beans should fully destroy the failed bean first
When it happens
Trigger: Producer/consumer A with clientId X fails to start (e.g. cannot reach NameServer); code catches the exception and calls start() again on the same object, or creates another consumer that hashes to the same clientId — the switch hits case START_FAILED and throws immediately.
Common situations: Retry loops around consumer.start() after a transient NameServer outage; hot re-creation of consumers/producer in the same JVM reusing an IP@instance naming pattern that collides on clientId; frameworks (Spring context refresh) restarting beans whose instance previously failed; mixing manual shutdown semantics so the failed instance is never removed from MQClientManager.
Related errors
- The consumer group[{consumerGroup}] has been created before,
- The PullConsumer service state not OK, maybe started once, {
- Failed to load rocksdb for auth_acl, please check whether it
- The consumer not running, please start it first.
- Subscribe and assign are mutually exclusive.
AI-assisted analysis of apache/rocketmq@293f588571 (2026-08-14).
Data as JSON: /api/errors/8440aa3bbf5a5894.
Report an issue: GitHub.