apache/cassandra · error · IllegalStateException
Source %s for %s is not remaining as a replica after the mov
Error message
Source %s for %s is not remaining as a replica after the move, can't do a consistent range movement, retry with that disabled
What it means
Thrown by Move.addSource during consistent (strict) range move planning. A source replica of a range would no longer be a replica of that range after the move, which breaks the guarantee that a transient replica being removed can safely skip streaming. In strict mode this is fatal; in non-strict mode MoveMultiRange skips the source instead.
Source
Thrown at src/java/org/apache/cassandra/tcm/sequences/Move.java:545
{
if (fd.isAlive(source.endpoint()))
{
if (source.isFull())
{
assert fullSource == null;
fullSource = source;
}
else
{
assert transientSource == null;
if (!destination.isSelf() && !source.isSelf())
{
// a transient replica is being removed, now, to be able to safely skip streaming from this
// replica we need to make sure it remains a replica for the range after the move has finished:
if (writeAdditions.get(source.endpoint()).byRange().get(destination.range()) == null)
{
if (strict)
throw new IllegalStateException(String.format("Source %s for %s is not remaining as a replica after the move, can't do a consistent range movement, retry with that disabled", source, destination));
else
return false;
}
return true;
}
else
{
transientSource = source;
}
}
return true;
}
else if (strict)
throw new IllegalStateException("Strict consistency requires the node losing the range to be UP but " + source + " is DOWN");
return false;
}
private void addToMovements(Replica destination, EndpointsByReplica.Builder movements)View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Retry the operation with consistent range movement (strict consistency) disabled, as the message suggests
- Adjust the move plan / token assignment so the source remains a replica (full or transient) of the range after the move
- Verify transient replication configuration (replication factor and transient replica counts) allows every removed transient source to remain a replica elsewhere
- Perform the movement in smaller steps (per-range) so strict invariants hold at each step
Example fix
// before MoveMultiRange.move(systemKeyspace, ranges, /* strict */ true); // after MoveMultiRange.move(systemKeyspace, ranges, /* strict */ false); // or fix placement so source remains a replica
Defensive patterns
Strategy: retry
Validate before calling
// before strict move: ensure each transient source remains a replica of its destination range
for (Replica source : sources)
if (writeAdditions.get(source.endpoint()).byRange().get(destination.range()) == null)
throw new PreconditionFailed(source + " will not remain a replica; use non-strict or fix placement"); Try / catch
try { move(ranges, true); }
catch (IllegalStateException e) { if (e.getMessage().contains("not remaining as a replica")) move(ranges, false); else throw e; } Prevention
- Validate replica placement after the planned move before executing
- Prefer non-strict consistency when transient replication is in play
- Run topology changes in small per-range steps
When it happens
Trigger: Running a consistent range movement (strict consistency enabled, e.g. nodetool move/rebuild with strict consistency or MoveMultiRange) where a transient source replica's writeAdditions entry has no matching range for the destination, i.e. the node is not staying a replica of destination.range() after the move.
Common situations: Operator-driven topology changes (moving tokens, decommission/bootstrap combinations) in multi-DC or transient-replication (EVERYWHERE/2-of-3 RF with transient replica counts) setups where the move leaves a range with too few full replicas; retry loops that previously used non-strict consistency now running strict.
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
- Unable to find sufficient sources for streaming range " + tr
- Multiple strict sources found for %s, sources: %s
- Cannot begin paxos auto repair for %s in %s.%s, multiple pen
- Node should be either source or destination in the movement
- Unable to move
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/0e1a1614e3c110a7.
Report an issue: GitHub.