apache/cassandra · error · IllegalStateException

Can't unregister node(s):

Error message

Can't unregister node(s):

What it means

Thrown by CMSOperations.unregisterLeftNodes when one or more nodes cannot be unregistered because their current NodeState does not permit it. The message lists each node with a state-specific remediation hint.

Solutions

  1. Inspect the reported per-node messages: wait until the leave operation completes, then retry.
  2. Complete or abort any in-progress decommission/leave for the blocking nodes.
  3. Verify each node's NodeState via cluster metadata before re-running unregister.

Example fix

// before
nodetool unregister nodeA nodeB // nodeB still LEAVING
// after
# wait for nodeB decommission to finish, then:
nodetool unregister nodeA nodeB
Defensive patterns

Strategy: validation

Validate before calling

for (NodeId id : nodeIds) { NodeState st = ClusterMetadata.current().plan.get(id).state(); if (st != NodeState.LEFT) throw new IllegalStateException(id + " not LEFT yet (" + st + "); wait for leave to complete"); }

Try / catch

try { ops.unregisterLeftNodes(nodeIds); } catch (IllegalStateException e) { logger.warn("Unregister deferred: {}", e.getMessage()); }

Prevention

When it happens

Trigger: Calling unregisterLeftNodes with node ids whose cluster metadata state is not LEFT (e.g. still LEAVING, decommission in progress, or in some other non-removable state).

Common situations: Running nodetool unregister on nodes whose decommission has not finished, batch-unregistering nodes where one is mid-leave, or retrying too soon after a failed decommission.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/659e5efc3803bde6. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/tcm/CMSOperations.java:348

                switch (nodeState)
                {
                    case REGISTERED:
                    case BOOTSTRAPPING:
                    case BOOT_REPLACING:
                        message.append(" - need to use `nodetool abortbootstrap` instead of unregistering").append('\n');
                        break;
                    case JOINED:
                        message.append(" - use `nodetool decommission` or `nodetool removenode` to remove this node").append('\n');
                        break;
                    case MOVING:
                        message.append(" - wait until move has been completed, then use `nodetool decommission` or `nodetool removenode` to remove this node").append('\n');
                        break;
                    case LEAVING:
                        message.append(" - wait until leave-operation has completed, then retry this command").append('\n');
                        break;
                }
            }
            throw new IllegalStateException("Can't unregister node(s):\n" + message);
        }

        for (NodeId nodeId : nodeIds)
        {
            logger.info("Unregistering " + nodeId);
            cms.commit(new Unregister(nodeId, EnumSet.of(NodeState.LEFT), ClusterMetadataService.instance().placementProvider()));
        }
    }

    public Map<Long, Map<String, String>> dumpDirectory(boolean tokens)
    {
        Map<Long, Map<String, Object>> directory = ClusterMetadataDirectoryTable.directory(tokens);
        return convertToStringValues(directory);
    }

    public Map<Long, Map<String, String>> dumpLog(long startEpoch, long endEpoch)
    {
        Map<Long, Map<String, Object>> log = ClusterMetadataLogTable.log(startEpoch, endEpoch);

View on GitHub (pinned to 88fd0f6a0e)