aeron-io/aeron · error · ClusterException
existing consensus module detected for clusterId=
Error message
existing consensus module detected for clusterId=<clusterId>
What it means
During ConsensusModule startup (conclude/onStart), the module checks the Aeron driver's counters for an existing 'Consensus Module state' counter matching the configured clusterId. If one already exists, another consensus module instance is (or was) using the same driver/media driver for this cluster, so a second module would corrupt cluster state. Aeron throws ClusterException to abort the duplicate startup.
Solutions
- Ensure the previous ConsensusModule/Aeron client is fully closed (close() in finally/shutdown hook) before starting a new one.
- Use a distinct clusterId for each cluster/member, or connect to a different (dedicated) media driver.
- If restarting after a crash, terminate the old media driver or clear its counters; for embedded drivers recreate the driver process.
- If moduleStateCounter was captured externally, pass the existing counter instead of letting conclude() detect a duplicate.
Example fix
// before Aeron aeron = Aeron.connect(); ConsensusModule module = ConsensusModule.launch(moduleCtx.aeron(aeron).clusterId(0)); ConsensusModule second = ConsensusModule.launch(moduleCtx2.aeron(aeron).clusterId(0)); // throws // after ConsensusModule second = ConsensusModule.launch(moduleCtx2.aeron(aeron).clusterId(1)); // distinct clusterId
Defensive patterns
Strategy: try-catch
Validate before calling
// before launch
CountersReader counters = aeron.countersReader();
if (Aeron.NULL_VALUE != ClusterCounters.find(counters, CONSENSUS_MODULE_STATE_TYPE_ID, clusterId)) {
throw new IllegalStateException("consensus module already running for clusterId=" + clusterId);
} Try / catch
try { ConsensusModule.launch(ctx); } catch (ClusterException e) { if (e.getMessage().contains("existing consensus module detected")) { closePreviousModuleAndRetry(); } else { throw e; } } Prevention
- Always close() the previous ConsensusModule in a shutdown hook
- Use a unique clusterId per cluster in shared drivers
- In tests, recreate the media driver between runs
When it happens
Trigger: Launching a second ConsensusModule with the same clusterId while a previous one is still connected to the same Aeron driver, or restarting after a crash that left the stale counter allocated in a still-running embedded driver.
Common situations: Accidentally starting two nodes in the same JVM/driver during testing; a previous ConsensusModule not fully closed (missing close()) before re-launching; embedded-driver test harnesses reusing a driver across runs; container restart where the media driver survives.
Related errors
- found existing archive for archiveId=
- zero services are only supported when…
- existing max write time counter detected for archiveId=
- no driver heartbeat detected
- The type for counterId=
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/9b25ab4183202584.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-cluster/src/main/java/io/aeron/cluster/ConsensusModule.java:1937
{
throw new ClusterException("error counter must be supplied if aeron client is");
}
if (null == countedErrorHandler)
{
countedErrorHandler = new CountedErrorHandler(errorHandler, errorCounter);
if (ownsAeronClient)
{
aeron.context().errorHandler(countedErrorHandler);
}
}
if (null == moduleStateCounter)
{
final CountersReader counters = aeron.countersReader();
if (Aeron.NULL_VALUE != ClusterCounters.find(counters, CONSENSUS_MODULE_STATE_TYPE_ID, clusterId))
{
throw new ClusterException("existing consensus module detected for clusterId=" + clusterId);
}
moduleStateCounter = ClusterCounters.allocate(
aeron, buffer, "Consensus Module state", CONSENSUS_MODULE_STATE_TYPE_ID, clusterId);
}
validateCounterTypeId(aeron, moduleStateCounter, CONSENSUS_MODULE_STATE_TYPE_ID);
if (null == electionStateCounter)
{
electionStateCounter = ClusterCounters.allocate(
aeron, buffer, "Cluster election state", ELECTION_STATE_TYPE_ID, clusterId);
}
validateCounterTypeId(aeron, electionStateCounter, ELECTION_STATE_TYPE_ID);
if (null == electionCounter)
{
electionCounter = ClusterCounters.allocate(View on GitHub (pinned to 6d60124e15)