apache/cassandra · error · java.lang.IllegalStateException
A node with address already exists, cancelling join. Use…
Error message
A node with address %s already exists, cancelling join. Use cassandra.replace_address if you want to replace this node.
What it means
Thrown during Register.register() when the broadcast address the node is joining with already maps to an existing peer in cluster metadata, and the node is not configured to replace that node. CMS refuses to register a duplicate address to keep the directory consistent.
Solutions
- Set cassandra.replace_address (or replace_node) to indicate intentional replacement of the existing node
- Give the new node a unique broadcast_address/port not present in the cluster
- If the old node is dead, remove it from the cluster (nodetool decommission/removenode) before reusing the address
- Verify with nodetool status that no live/registered node holds that IP
Example fix
// before cassandra.broadcast_address=10.0.0.7 // already used by node2 // after cassandra.broadcast_address=10.0.0.9 // unused address // or, for intentional replacement: -Dcassandra.replace_address=10.0.0.7
Defensive patterns
Strategy: validation
Validate before calling
// before starting a node, check the address is free
boolean taken = ClusterMetadata.current().directory.peerId(broadcastAddress) != null;
if (taken && !isReplacementConfigured()) throw new IllegalStateException("address in use; set replace_address or pick a new IP"); Try / catch
try { CMS.commit(registration); } catch (IllegalStateException e) { if (e.getMessage().contains("already exists")) { /* resolve duplicate address or set replace_address */ } else throw e; } Prevention
- Run `nodetool status` before assigning IPs to new nodes
- Never clone node images with the same broadcast_address
- Decommission dead nodes before reusing their addresses
When it happens
Trigger: Calling register() where directory.peerId(broadcastAddress) is non-null but the node is not doing an explicit replacement (no cassandra.replace_address / replace_node configured).
Common situations: Cloning a VM/image with the same IP as an existing node; a previously replaced node's old entry still in metadata; accidental reuse of an assigned IP; starting a second node with a misconfigured broadcast_address.
Related errors
- Node has host id in system.local, but is not present in…
- Tried to replace same address, but node does not seem to be…
- A node required to move the data consistently is down
- Booting with ClusterMetadata from file:
- Bootstrap can be started exactly once, but seems to have…
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/7f83c3476748d2c8.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/tcm/transformations/Register.java:152
{
return register(nodeAddresses, DatabaseDescriptor.getLocator().local(), nodeVersion);
}
private static NodeId register(NodeAddresses nodeAddresses, Location location, NodeVersion nodeVersion)
{
ClusterMetadata metadata = ClusterMetadata.current();
DatabaseDescriptor.getInitialLocationProvider().validate(metadata);
NodeId nodeId = metadata.directory.peerId(nodeAddresses.broadcastAddress);
if (nodeId == null || metadata.directory.peerState(nodeId) == NodeState.LEFT)
{
if (nodeId != null)
ClusterMetadataService.instance().commit(new Unregister(nodeId, EnumSet.of(NodeState.LEFT), ClusterMetadataService.instance().placementProvider()));
Register registration = new Register(nodeAddresses, location, nodeVersion);
nodeId = ClusterMetadataService.instance().commit(registration).directory.peerId(nodeAddresses.broadcastAddress);
}
else
{
throw new IllegalStateException(String.format("A node with address %s already exists, cancelling join. Use cassandra.replace_address if you want to replace this node.", nodeAddresses.broadcastAddress));
}
logger.info("Registered with endpoint {}, node id: {}", nodeAddresses.broadcastAddress, nodeId);
return nodeId;
}
private static NodeId register(boolean force)
{
// Try to recover node ID from the system keyspace
UUID localHostId = SystemKeyspace.getLocalHostId();
Directory directory = ClusterMetadata.current().directory;
if (force || localHostId == null)
{
NodeId nodeId = register(NodeAddresses.current());
localHostId = nodeId.toUUID();
SystemKeyspace.setLocalHostId(localHostId);
logger.info("New node ID obtained {}, (Note: This should happen exactly once per node)", localHostId);
return nodeId;View on GitHub (pinned to 88fd0f6a0e)