apache/cassandra · error · UnsupportedOperationException
Cannot remove self
Error message
Cannot remove self
What it means
removeNode refuses to remove a node by host ID when the requested NodeId equals the caller's own node ID, throwing UnsupportedOperationException. Removing yourself from the ring must go through the decommission path instead, which drains tokens gracefully.
Solutions
- Use `nodetool decommission` on the local node instead of removenode for self-removal.
- Re-run removenode with the host ID of the actual dead node (`nodetool status` to list host IDs).
- Verify the target ID with `nodetool statusbatch` / `nodetool status` before removal.
Example fix
// before
nodetool removenode $(nodetool info | awk '/Host ID/{print $4}') # own ID
// after
String targetId = deadNodeHostId; // from nodetool status of another node
if (!targetId.equals(localHostId)) nodetool.removenode(targetId); Defensive patterns
Strategy: validation
Validate before calling
String targetHostId = args[0];
String localHostId = SystemKeyspace.getLocalHostId().toString();
if (targetHostId.equals(localHostId))
throw new IllegalArgumentException("Refusing removenode of self; use `nodetool decommission` instead"); Try / catch
try {
storageService.removeNode(hostId);
} catch (UnsupportedOperationException e) {
if (e.getMessage().equals("Cannot remove self")) {
// correct operation for self-removal is decommission
storageService.decommission();
} else throw e;
} Prevention
- Compare the requested host ID against the local host ID before calling removenode.
- Use decommission for planned self-removal; removenode only for dead nodes.
- Automate runbooks to fetch the target ID from `nodetool status`, not local info.
- Document the decommission-vs-removenode distinction in ops guides.
When it happens
Trigger: Invoking `nodetool removenode <hostId>` on a node passing its own host ID, which routes to SingleNodeSequences.removeNode with toRemove == metadata.myNodeId().
Common situations: Operator intends to decommission the local node but types its own host ID into removenode; copy/paste error in a runbook; scripted removal grabs the wrong node ID from a listing.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Host ID not found.
- Allocated token already assigned to node . Is another node…
- Can not commit transformation
- Can not remove a node that has an in-progress sequence
- Can't force remove completion, abort the remove operation…
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/ec7735310160a0b1.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/tcm/sequences/SingleNodeSequences.java:131
}
static void abortDecommission(String nodeId)
{
abortHelper(nodeId, MultiStepOperation.Kind.LEAVE, DECOMMISSION_FAILED);
}
/**
* Entrypoint to begin node removal process
*
* @param toRemove id of the node to remove
* @param force if set to true, will remove the node even if this would mean there will be not enough nodes
* to satisfy replication factor
*/
static void removeNode(NodeId toRemove, boolean force)
{
ClusterMetadata metadata = ClusterMetadata.current();
if (toRemove.equals(metadata.myNodeId()))
throw new UnsupportedOperationException("Cannot remove self");
InetAddressAndPort endpoint = metadata.directory.endpoint(toRemove);
if (endpoint == null)
throw new UnsupportedOperationException("Host ID not found.");
if (Gossiper.instance.getLiveMembers().contains(endpoint))
throw new UnsupportedOperationException("Node " + endpoint + " is alive and owns this ID. Use decommission command to remove it from the ring");
NodeState removeState = metadata.directory.peerState(toRemove);
if (removeState == null)
throw new UnsupportedOperationException("Node to be removed is not a member of the token ring");
if (removeState == NodeState.LEAVING)
logger.warn("Node {} is already leaving or being removed, continuing removal anyway", endpoint);
if (metadata.inProgressSequences.contains(toRemove))
throw new UnsupportedOperationException("Can not remove a node that has an in-progress sequence");
ReconfigureCMS.maybeReconfigureCMS(metadata, endpoint);
logger.info("starting removenode with {} {}", metadata.epoch, toRemove);View on GitHub (pinned to 88fd0f6a0e)