apache/cassandra · info

Token changing ownership from to

Error message

Token {} changing ownership from {} to {}

What it means

LegacyStateListener.logCompletedReplacement warns, for each token a replacement sequence moves, that ownership of that token is changing from the replaced node to the replacement node. It is an informational migration log emitted while applying TCM sequences to legacy local/remote state (processChangesToLocalState / processChangesToRemotePeers callers).

Solutions

  1. If intended, no action: this confirms token ranges moved to the replacement node; run repair afterwards.
  2. Verify streaming finished and ranges are consistent (nodetool netsso/repair) after replacement.
  3. If replacement was accidental, check the replace_address config and correct node identity before further bootstraps.
  4. Monitor pending ranges drain so clients stop routing to the replaced node.
Defensive patterns

Strategy: try-catch

Try / catch

// This is an informational log during replacement; guard the replacement itself
try {
    startReplacement(replaced, replacement);
} catch (Exception e) {
    logger.error("Replacement initiation failed; tokens not moved", e);
}

Prevention

When it happens

Trigger: A StartReplace/sequence completes via LegacyStateListener.processChanges when a node bootstraps with the 'replace' option: directory.endpoint(sequence.startReplace.replacement()) resolves the replacement, GossipHelper.getTokensFromOperation yields the moved tokens, and each token's ownership change is logged.

Common situations: Replacing a dead node with cassandra.replace_address; operator-driven replacement during hardware failover; accidental replacements triggered with wrong replace_address should be checked if token ownership shifts unexpectedly.

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

Appendix: source

Thrown at src/java/org/apache/cassandra/tcm/listeners/LegacyStateListener.java:245

    {
        for (InetAddressAndPort remove : removed)
        {
            GossipHelper.removeAndEvict(remove);
            PeersTable.removeFromSystemPeersTables(remove);
        }
    }

    private void logCompletedReplacement(Directory directory, BootstrapAndReplace sequence)
    {
        // legacy log message for compatibility (& tests)
        InetAddressAndPort replaced = directory.endpoint(sequence.startReplace.replaced());
        InetAddressAndPort replacement = directory.endpoint(sequence.startReplace.replacement());
        Collection<Token> tokens = GossipHelper.getTokensFromOperation(sequence);
        logger.info("Node {} will complete replacement of {} for tokens {}", replacement, replaced, tokens);
        if (!replacement.equals(replaced))
        {
            for (Token token : tokens)
                logger.warn("Token {} changing ownership from {} to {}", token, replaced, replacement);
        }
    }

    private boolean directoryEntryChangedFor(NodeId nodeId, Directory prev, Directory next)
    {
        return prev.peerState(nodeId) != next.peerState(nodeId) ||
               !Objects.equals(prev.getNodeAddresses(nodeId), next.getNodeAddresses(nodeId)) ||
               !Objects.equals(prev.version(nodeId), next.version(nodeId)) ||
               !Objects.equals(prev.location(nodeId), next.location(nodeId));

    }
}

View on GitHub (pinned to 88fd0f6a0e)