apache/cassandra · error · java.lang.IllegalStateException
Node has host id in system.local, but is not present in…
Error message
Node has host id %s in system.local, but is not present in cluster metadata - not allowing this node to register. If a bootstrap of this node failed and was aborted with `nodetool abortbootstrap` it should also have its data removed before trying to rebootstrap.
What it means
Thrown during registration when system.local contains a host id but cluster metadata's directory has no NodeId for this node's broadcast address. CMS trusts cluster metadata as the source of truth; a local host id with no corresponding metadata entry is treated as residue from a failed/aborted bootstrap and registration is blocked.
Solutions
- Wipe the node's data directories (including system keyspaces) so system.local is regenerated, then rebootstrap
- If aborting a failed bootstrap, always follow `nodetool abortbootstrap` with data directory cleanup
- If the node should be a member, restore/verify cluster metadata (cms tool) so it contains this node
Example fix
# before rebootstrap after abortbootstrap nodetool abortbootstrap # after: also clean data cassandra-stale... -> rm -rf /var/lib/cassandra/data/* # then restart to rebootstrap cleanly
Defensive patterns
Strategy: validation
Validate before calling
// before re-registering a node with stale data
UUID localHostId = SystemKeyspace.getLocalHostId();
if (localHostId != null && ClusterMetadata.current().directory.peerId(broadcastAddress) == null) {
// stale system.local: wipe data dirs before rebootstrap
} Try / catch
try { register(); } catch (IllegalStateException e) { if (e.getMessage().startsWith("Node has host id")) { /* clean data dirs and rebootstrap */ } else throw e; } Prevention
- Always follow `nodetool abortbootstrap` with data directory cleanup
- Never restore another cluster's data snapshot without wiping system.local
- Keep cluster metadata and local state in sync when re-imaging nodes
When it happens
Trigger: register() finds localHostId in system.local, is not doing replacement, and directory.peerId(broadcastAddress) returns null.
Common situations: Re-bootstrapping a node whose previous bootstrap failed and was aborted with `nodetool abortbootstrap` but whose data (including system.local) was left in place; restoring a node from a snapshot into a fresh cluster.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- A node with address already exists, cancelling join. Use…
- 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/6ac9e4bf8f92a676.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/tcm/transformations/Register.java:180
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;
}
else if (NodeId.isValidNodeId(localHostId) && directory.peerIds().contains(NodeId.fromUUID(localHostId)))
{
return NodeId.fromUUID(localHostId);
}
else
{
NodeId nodeId = directory.peerId(FBUtilities.getBroadcastAddressAndPort());
if (nodeId == null)
throw new IllegalStateException("Node has host id "+localHostId+" in system.local, but is not present in cluster metadata - not allowing this node to register. " +
"If a bootstrap of this node failed and was aborted with `nodetool abortbootstrap` it should also have its data removed before trying to rebootstrap.");
NodeVersion dirVersion = directory.version(nodeId);
// If this is a node in the process of upgrading, update the host id in the system.local table
// TODO: when constructing the initial cluster metadata for upgrade, we include a mapping from
// NodeId to the old HostId. We will need to use this lookup to map between the two for
// hint delivery immediately following an upgrade.
if (dirVersion == null || !dirVersion.isUpgraded())
{
if (directory.hostId(nodeId).equals(localHostId))
{
SystemKeyspace.setLocalHostId(nodeId.toUUID());
logger.info("Updated local HostId from pre-upgrade version {} to the one which was pre-registered " +
"during initial cluster metadata conversion {}", localHostId, nodeId.toUUID());
}
else
{
throw new RuntimeException("HostId read from local system table does not match the one recorded " +View on GitHub (pinned to 88fd0f6a0e)