apache/cassandra · error · IllegalArgumentException

Another sequence of kind

Error message

Another sequence of kind ${kind} is in progress for node ${nodeIpOrId}. Cannot proceed with move.

What it means

finishInProgressSequence resumes an existing MOVE sequence, so it requires that the node's in-progress sequence actually be a MOVE. If inProgressSequences.get(nodeId).kind() is anything else, this IllegalArgumentException is thrown to prevent mixing a token argument with a different operation.

Solutions

  1. Run the subcommand matching the in-progress sequence kind (e.g. resume/abort the JOIN or REPLACE) instead of move.
  2. Finish or cancel the other sequence first, then start a fresh MOVE with a --token.
  3. Verify the node's in-progress sequence kind from the metadata before invoking move.

Example fix

// before
bin/cms move -ip 10.0.0.5 --token 1234   // JOIN in progress
// after
bin/cms <join-resume-or-abort> -ip 10.0.0.5
bin/cms move -ip 10.0.0.5 --token 1234
Defensive patterns

Strategy: validation

Validate before calling

MultiStepOperation<?> op = meta.inProgressSequences.get(nodeId);
if (op != null && op.kind() != MultiStepOperation.Kind.MOVE)
    throw new IllegalStateException("Sequence " + op.kind() + " in progress; move cannot resume it");

Try / catch

try { tool.move(nodeId, token); } catch (IllegalArgumentException e) { if (e.getMessage().contains("Cannot proceed with move")) { runMatchingSequenceCommand(); } else throw e; }

Prevention

When it happens

Trigger: Calling finishInProgressSequence (reached via updatedMetadata) when the node has an in-progress sequence of a non-MOVE kind (JOIN, REPLACE, REBUILD, etc.) while running the move command.

Common situations: Operator confuses an in-progress bootstrap with a move and passes --token; leftover non-MOVE sequence in the metadata snapshot makes the tool think it should resume a move.

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

Appendix: source

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

                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.");
            }

            Move moveInProgress = (Move) multiStepOperation;
            Collection<Token> inProgressTokens = moveInProgress.tokens;
            Collection<Token> givenTokenSet;
            if (token == null)
            {
                givenTokenSet = Set.of();
            }
            else
            {
                metadata.partitioner.getTokenFactory().validate(token);
                givenTokenSet = Set.of(metadata.partitioner.getTokenFactory().fromString(token));
            }
            if (givenTokenSet.isEmpty() || new HashSet<>(moveInProgress.tokens).equals(givenTokenSet))
            {

View on GitHub (pinned to 88fd0f6a0e)