apache/cassandra · error · java.lang.IllegalArgumentException

target token is already owned by another node.

Error message

target token %s is already owned by another node.

What it means

move checks ClusterMetadata.current().tokenMap.tokens() and throws IllegalArgumentException if the requested target token is already assigned to some node in the ring. Tokens must be unique; moving onto an owned token would corrupt ownership ranges.

Solutions

  1. Choose a token not present in the ring: run `nodetool ring` (or query ClusterMetadata.tokenMap) and pick an unowned token.
  2. If the token belongs to a stale/removed node, finish removing that node first (removenode), then retry.
  3. Use a load-balancing tool or omit the explicit token so a balanced unowned token is chosen automatically.

Example fix

// before
ss.move(existingToken); // IllegalArgumentException
// after
Set<Token> owned = ClusterMetadata.current().tokenMap.tokens();
if (!owned.contains(newToken)) ss.move(newToken);
Defensive patterns

Strategy: validation

Validate before calling

if (ClusterMetadata.current().tokenMap.tokens().contains(newToken))
    throw new IllegalArgumentException("token already owned: " + newToken);

Try / catch

try { move(token); }
catch (IllegalArgumentException e) { if (e.getMessage().contains("already owned")) { pickUnownedToken(); } else throw e; }

Prevention

When it happens

Trigger: Running `nodetool move <token>` with a token that already exists in the ring - e.g. copying another node's token, reusing a token from a removed node that is still registered, or computing a token that collides with an existing one.

Common situations: Rebalancing scripts that hardcode tokens from a stale ring snapshot; attempting to move a node onto the token of a node removed earlier but still present in cluster metadata; initial_token reuse across nodes.

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/82908091d059ce63. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/tcm/sequences/SingleNodeSequences.java:178

    {
        abortHelper(nodeId, MultiStepOperation.Kind.REMOVE, null);
    }

    /**
     * move the node to new token or find a new token to boot to according to load
     *
     * @param newToken new token to boot to, or if null, find balanced token to boot to
     */
    static void move(Token newToken)
    {
        if (ClusterMetadataService.instance().isMigrating() || ClusterMetadataService.state() == ClusterMetadataService.State.GOSSIP)
            throw new IllegalStateException("This cluster is migrating to cluster metadata, can't move until that is done.");

        if (newToken == null)
            throw new IllegalArgumentException("Can't move to the undefined (null) token.");

        if (ClusterMetadata.current().tokenMap.tokens().contains(newToken))
            throw new IllegalArgumentException(String.format("target token %s is already owned by another node.", newToken));

        // address of the current node
        ClusterMetadata metadata = ClusterMetadata.current();
        NodeId self = metadata.myNodeId();
        // This doesn't make any sense in a vnodes environment.
        if (metadata.tokenMap.tokens(self).size() > 1)
        {
            logger.error("Invalid request to move(Token); This node has more than one token and cannot be moved thusly.");
            throw new UnsupportedOperationException("This node has more than one token and cannot be moved thusly.");
        }

        ClusterMetadataService.instance().commit(new PrepareMove(self,
                                                                 Collections.singleton(newToken),
                                                                 ClusterMetadataService.instance().placementProvider(),
                                                                 true),
                                                 m -> m,
                                                 failureHandler("PrepareMove", StorageService.instance::markMoveFailed));
        InProgressSequences.finishInProgressSequences(self);

View on GitHub (pinned to 88fd0f6a0e)