apache/cassandra · error · IllegalArgumentException

Target token is already owned by node

Error message

Target token ${toToken} is already owned by node ${tokenOwnerId}

What it means

When starting a new MOVE, the target token must not already be assigned to another node in metadata.tokenMap. If tokenMap.tokens() contains toToken, the tool throws this IllegalArgumentException naming the current owner, since moving the node there would create a duplicate token ownership.

Solutions

  1. Pick an unowned token (e.g. a value not present in `nodetool ring` output) and re-run with that --token.
  2. If the token belongs to a decommissioned node, first remove that node's leftover token/state from the ring.
  3. Compute a balanced token assignment before moving to avoid collisions.

Example fix

// before
bin/cms move -ip 10.0.0.5 --token 1234   // owned by node 2
// after
bin/cms move -ip 10.0.0.5 --token 9876543210   // unowned token
Defensive patterns

Strategy: validation

Validate before calling

Token toToken = meta.partitioner.getTokenFactory().fromString(token);
if (meta.tokenMap.tokens().contains(toToken))
    throw new IllegalArgumentException("Token " + token + " already owned by " + meta.tokenMap.owner(toToken));

Try / catch

try { tool.move(nodeId, token); } catch (IllegalArgumentException e) { if (e.getMessage().contains("already owned by node")) { pickUnownedTokenAndRetry(); } else throw e; }

Prevention

When it happens

Trigger: Move subcommand in `execute` with a --token value that metadata.tokenMap.owner(toToken) shows is already owned by a different node.

Common situations: Operator copies a token from another node's output or reuses a token from a decommissioned node whose entry still exists; token collision after manual token assignment.

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


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

Appendix: source

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

            NodeId nodeId = nodeIdentifierOption.getNodeId(metadata);

            if (metadata.inProgressSequences.contains(nodeId))
            {
                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() +

View on GitHub (pinned to 88fd0f6a0e)