aeron-io/aeron · error · ClusterException
ConsensusModule.Context.clusterMembers must be set
Error message
ConsensusModule.Context.clusterMembers must be set
What it means
A ConsensusModule needs the full list of cluster member endpoints to canvas for a leader and form/maintain consensus. conclude() requires Context.clusterMembers to be explicitly set; a null value is a configuration error thrown as a ClusterException.
Solutions
- Call ctx.clusterMembers("memberId,clientFacingIngress,memberFacing,log,archive,events|..."), e.g. "0,localhost:20000,localhost:20001,localhost:20002,localhost:20003,localhost:20004"
- Set the system property aeron.cluster.cluster.members for the clusterio launcher
- Use ClusterMembership tools or the same string on all members with consistent member IDs
Example fix
// before
new ConsensusModule.Context()
.ingressChannel("aeron:udp?endpoint=localhost:20000"); // no clusterMembers
// after
new ConsensusModule.Context()
.ingressChannel("aeron:udp?endpoint=localhost:20000")
.clusterMembers("0,localhost:20000,localhost:20001,localhost:20002,localhost:20003,localhost:20004"); Defensive patterns
Strategy: validation
Validate before calling
if (ctx.clusterMembers() == null) {
throw new IllegalStateException("ConsensusModule.Context.clusterMembers must be set before conclude()");
} Try / catch
try { ctx.conclude(); } catch (ClusterException e) { if (e.getMessage().contains("clusterMembers must be set")) { /* load cluster config and retry setup */ } } Prevention
- Centralize cluster member strings in one config source shared by all nodes
- Validate the members string format (comma-separated six fields per member) before startup
- Include clusterMembers in startup smoke tests
When it happens
Trigger: Building a ConsensusModule.Context (or using the standalone-cluster launcher) without calling clusterMembers(...) before conclude().
Common situations: Omitting -Daeron.cluster.cluster.members on the command line; writing a custom main() that sets channels/ports but forgets clusterMembers; migrating from single-node setups that tolerated defaults in older Aeron versions.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- not found in
- clusterMembers and endpoints differ
- incompatible time unit
- logSessionId was null, should always have a value
- invalid clusterSessionId= expected=
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/0a3fd371897cdb19.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-cluster/src/main/java/io/aeron/cluster/ConsensusModule.java:1772
markFileDir = markFileDir.getCanonicalFile();
if (Strings.isEmpty(clusterServicesDirectoryName))
{
clusterServicesDirectoryName = clusterDirectoryName;
}
else
{
clusterServicesDirectoryName = new File(clusterServicesDirectoryName).getCanonicalPath();
}
}
catch (final IOException ex)
{
throw new UncheckedIOException(ex);
}
if (null == clusterMembers)
{
throw new ClusterException("ConsensusModule.Context.clusterMembers must be set");
}
if (deleteDirOnStart)
{
IoUtil.delete(clusterDir, false);
}
IoUtil.ensureDirectoryExists(clusterDir, "cluster");
IoUtil.ensureDirectoryExists(markFileDir, "mark file");
if (startupCanvassTimeoutNs / leaderHeartbeatTimeoutNs < 2)
{
throw new ClusterException(
"startupCanvassTimeoutNs=" + startupCanvassTimeoutNs +
" must be a multiple of leaderHeartbeatTimeoutNs=" + leaderHeartbeatTimeoutNs);
}
if (null == clusterClock)View on GitHub (pinned to 6d60124e15)