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

  1. 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
  2. Give every client a unique instanceName (setInstanceName) so a failed instance cannot poison another client sharing the same clientId
  3. Do not call start() twice on the same object after a failure — create a new instance instead
  4. 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

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


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