apache/cassandra · error · UnsupportedOperationException

This node has more than one token and cannot be moved…

Error message

This node has more than one token and cannot be moved thusly.

What it means

MOVE (as issued here) relocates a node's single token, so it only works for nodes that own exactly one token. If metadata.tokenMap.tokens(nodeId).size() > 1 the tool throws this UnsupportedOperationException because multi-token nodes cannot be moved this way.

Solutions

  1. Use a rebalancing workflow appropriate for vnodes (e.g. rebootstrap with desired num_tokens=1 or run a decommission/rejoin) instead of move.
  2. Rebuild the node with num_tokens set to 1 and chosen tokens, then move if needed.
  3. If single-token operation is required, migrate data off and re-add the node with one token.
Defensive patterns

Strategy: validation

Validate before calling

if (meta.tokenMap.tokens(nodeId).size() > 1)
    throw new UnsupportedOperationException("Node " + nodeId + " has " + meta.tokenMap.tokens(nodeId).size() + " tokens; move requires a single-token node");

Try / catch

try { tool.move(nodeId, token); } catch (UnsupportedOperationException e) { if (e.getMessage().contains("more than one token")) { useVnodeRebalanceFlow(); } else throw e; }

Prevention

When it happens

Trigger: Move subcommand in `execute` when the target node has more than one token assigned in metadata.tokenMap (e.g. vnodes configured with num_tokens > 1).

Common situations: Cluster was bootstrapped with vnodes; operator attempts `cms move` on such a node expecting it to work like a single-token cluster.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at src/java/org/apache/cassandra/tools/CMSOfflineTool.java:502

                ClusterMetadata updatedMetadata = finishInProgressSequence(nodeId, token, metadata);
                writeMetadata(output, updatedMetadata, outputFilePath);
                return;
            }

            if (null == token)
            {
                throw new IllegalArgumentException("Token required when no MOVE sequence is in progress.");
            }
            metadata.partitioner.getTokenFactory().validate(token);
            Token toToken = metadata.partitioner.getTokenFactory().fromString(token);
            if (metadata.tokenMap.tokens().contains(toToken))
            {
                NodeId tokenOwnerId = metadata.tokenMap.owner(toToken);
                throw new IllegalArgumentException("Target token " + toToken + " is already owned by node " + tokenOwnerId.id());
            }
            if (metadata.tokenMap.tokens(nodeId).size() > 1)
            {
                throw new UnsupportedOperationException("This node has more than one token and cannot be moved thusly.");
            }

            PrepareMove prepareMove = new PrepareMove(nodeId, Set.of(toToken), new UniformRangePlacement(), false);
            ClusterMetadata updatedMetadata = prepareMove.execute(metadata).success().metadata;
            updatedMetadata = updatedMetadata.inProgressSequences.get(nodeId).applyTo(updatedMetadata).success().metadata;
            writeMetadata(output, updatedMetadata, outputFilePath);
        }

        ClusterMetadata finishInProgressSequence(NodeId nodeId, String token, ClusterMetadata metadata)
        {
            MultiStepOperation<?> multiStepOperation = metadata.inProgressSequences.get(nodeId);
            if (multiStepOperation.kind() != MultiStepOperation.Kind.MOVE)
            {
                throw new IllegalArgumentException("Another sequence of kind " + multiStepOperation.kind() +
                                                   " is in progress for node " + nodeIdentifierOption.getNodeIpOrId() +
                                                   ". Cannot proceed with move.");
            }

View on GitHub (pinned to 88fd0f6a0e)