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

  1. Wipe the node's data directories (including system keyspaces) so system.local is regenerated, then rebootstrap
  2. If aborting a failed bootstrap, always follow `nodetool abortbootstrap` with data directory cleanup
  3. 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

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


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)