aeron-io/aeron · error · ClusterException
clusterMembers and endpoints differ
Error message
clusterMembers and endpoints differ: ${member.endpoints} != ${memberEndpoints} What it means
ClusterMember.validateMemberEndpoints compares the endpoints parsed from a member's entry in the clusterMembers config string against the memberEndpoints string supplied for that member. If they differ, it throws ClusterException. This guards against a member whose configured membership list and its own advertised endpoints disagree, which would break cluster connectivity.
Solutions
- Compare the member's entry in the clusterMembers list with aeron.cluster.member.endpoints and make them byte-for-byte identical (same endpoints in same order).
- Check for stale ports/hostnames after a migration and update both properties together.
- If generated by a tool, fix the generator so both values come from a single source of truth.
- Restart the node after correcting the configuration.
Example fix
// before -Daeron.cluster.members=0,hostA:20000,hostA:20001,hostA:20002,hostA:20003,hostA:20004|1,hostB:20000,... -Daeron.cluster.member.endpoints=hostA:20000,hostA:20001,hostA:20003,hostA:20004 // after (member-level endpoints must match the clusterMembers entry exactly) -Daeron.cluster.member.endpoints=hostA:20000,hostA:20001,hostA:20002,hostA:20003,hostA:20004
Defensive patterns
Strategy: validation
Validate before calling
// before starting the node
ClusterMember[] members = ClusterMember.parse(0, memberEndpointsConfigString);
ClusterMember thisMember = ClusterMember.findMember(members, ClusterMember.parse(NULL_VALUE, memberEndpoints));
if (thisMember == null) {
throw new IllegalArgumentException("member endpoints not found in clusterMembers list");
} Prevention
- Generate clusterMembers and aeron.cluster.member.endpoints from a single config source.
- Diff both endpoint strings after every config change.
- Validate endpoint parity in a startup script before launching the node.
When it happens
Trigger: Calling ClusterMember.validateMemberEndpoints(member, memberEndpoints) where member.endpoints (parsed from the clusterMembers string) does not exactly equal the parsed memberEndpoints string for that member (mismatched client-facing, member-facing, log, archive or replication endpoints).
Common situations: Startup validation of a cluster member where the clusterMembers system property and the member's own aeron.cluster.member.endpoints were edited independently; a copy-paste error leaving an old port or hostname in one of the two; automated config generation producing inconsistent values.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- not found in
- endpoint missing '=' separator:
- either a instance or class name for the service must be…
- service id outside allowed range
- Aeron client must use a RethrowingErrorHandler
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/5688b9c925146013.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-cluster/src/main/java/io/aeron/cluster/ClusterMember.java:1085
return member;
}
/**
* Check the member with the memberEndpoints.
*
* @param member to check memberEndpoints against.
* @param memberEndpoints to check member against.
* @see ConsensusModule.Context#memberEndpoints()
* @see ConsensusModule.Context#clusterMembers()
*/
public static void validateMemberEndpoints(final ClusterMember member, final String memberEndpoints)
{
final ClusterMember endpoints = ClusterMember.parseEndpoints(NULL_VALUE, memberEndpoints);
if (!areSameEndpoints(member, endpoints))
{
throw new ClusterException(
"clusterMembers and endpoints differ: " + member.endpoints + " != " + memberEndpoints);
}
}
/**
* Are two cluster members using the same endpoints?
*
* @param lhs to compare for equality.
* @param rhs to compare for equality.
* @return true if both are using the same endpoints or false if not.
*/
public static boolean areSameEndpoints(final ClusterMember lhs, final ClusterMember rhs)
{
return lhs.ingressEndpoint.equals(rhs.ingressEndpoint) &&
lhs.consensusEndpoint.equals(rhs.consensusEndpoint) &&
lhs.logEndpoint.equals(rhs.logEndpoint) &&
lhs.catchupEndpoint.equals(rhs.catchupEndpoint) &&
lhs.archiveEndpoint.equals(rhs.archiveEndpoint);View on GitHub (pinned to 6d60124e15)