apache/cassandra · warning
Host ID collision for
Error message
Host ID collision for {} between {} and {}; ignored {} What it means
Warning logged by GossipCMSListener.onJoin when a gossiping endpoint announces a host ID that is already registered in the TCM Directory to a different endpoint, and the old endpoint has a more recent startup generation (compareEndpointStartup > 0). The listener concludes this is a host ID collision (two nodes claiming the same host ID) rather than an IP change, ignores the new endpoint, and returns without updating metadata.
Solutions
- Identify the duplicate node (from the log: hostId, oldEndpoint, endpoint) and regenerate the duplicated node's host ID / rebuild it from scratch with its own data directory
- Ensure node images or snapshots are never cloned while retaining the same host ID file; provision each node uniquely
- Stop the offending (ignored) endpoint so it does not keep announcing a colliding identity, then re-bootstrap it properly
Example fix
// before: cloned VM keeps the same host ID cp -r /var/lib/cassandra /var/lib/cassandra-node2 # same host_id // after: clear identity state so a new host ID is generated on the clone rm /var/lib/cassandra-node2/hostid.txt && restart node2
Defensive patterns
Strategy: validation
Validate before calling
UUID hostId = UUID.fromString(hostIdValue.value);
NodeId existing = metadata.directory.nodeIdFromHostId(hostId);
if (existing != null && !metadata.directory.endpoint(existing).equals(endpoint)) {
logger.warn("Host ID {} already bound to {} - refusing to accept {}", hostId, metadata.directory.endpoint(existing), endpoint);
return;
} Prevention
- Never clone VMs/disks of provisioned nodes; always generate fresh host IDs
- Keep cassandra data/identity files out of golden images
- Alert on duplicate host IDs in cluster membership monitoring
When it happens
Trigger: onJoin (via onAlive) processes an endpoint state carrying a hostId whose nodeId already maps to oldEndpoint, and Gossiper.instance.compareEndpointStartup(oldEndpoint, endpoint) > 0, i.e. the announced endpoint claims to be newer but the directory already binds that host ID elsewhere.
Common situations: Cloning a node's VM/disk image (host ID duplicated); restoring a node from a snapshot of another node; misconfigured cassandra-rackdc/host-id state after a failed bootstrap; two nodes accidentally started with the same data directory.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Could not find NodeId for endpoint
- A node with address already exists, cancelling join. Use…
- Bad NodeState
- broadcast_address cannot be a wildcard address (
- Can't abort a operation for a node ( ) that is UP - run…
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/83a366c8dbc34f31.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/tcm/migration/GossipCMSListener.java:67
if (!metadata.epoch.is(Epoch.UPGRADE_GOSSIP))
return;
NodeId nodeId = metadata.directory.peerId(endpoint);
if (nodeId == null)
{
VersionedValue hostIdValue = epState.getApplicationState(ApplicationState.HOST_ID);
if (Gossiper.isHibernate(epState))
return;
if (hostIdValue != null)
{
UUID hostId = UUID.fromString(hostIdValue.value);
nodeId = metadata.directory.nodeIdFromHostId(hostId);
InetAddressAndPort oldEndpoint = metadata.directory.endpoint(nodeId);
if (Gossiper.instance.compareEndpointStartup(oldEndpoint, endpoint) > 0)
{
logger.warn("Host ID collision for {} between {} and {}; ignored {}", hostId, oldEndpoint, endpoint, endpoint);
return;
}
logger.info("Node {} (hostId = {}) changing IP from {} to {}", nodeId, hostId, oldEndpoint, endpoint);
Gossiper.instance.removeEndpoint(oldEndpoint);
}
else
{
logger.warn("Could not find NodeId for endpoint {}", endpoint);
return;
}
}
// only thing that can change is the release version and addresses
CassandraVersion gossipVersion = epState.getReleaseVersion();
NodeAddresses newAddresses = GossipHelper.getAddressesFromEndpointState(endpoint, epState);
while (true)
{
NodeVersion cmVersion = metadata.directory.versions.get(nodeId);
if (cmVersion.cassandraVersion.equals(gossipVersion) && newAddresses.equals(metadata.directory.getNodeAddresses(nodeId)))View on GitHub (pinned to 88fd0f6a0e)