apache/cassandra · error · IllegalStateException
Got duplicate initiate migration message from %s, migration
Error message
Got duplicate initiate migration message from %s, migration is already started by %s
What it means
Election.PrepareHandler.doVerb processes incoming TCM_INIT_MIG_REQ messages. If updateInitiator(null, initiator) fails, another migration initiation is already in progress, so the handler throws IllegalStateException reporting both the sender and the existing initiator. This is the message-driven counterpart of the nominateSelf duplicate-initiation check.
Source
Thrown at src/java/org/apache/cassandra/tcm/migration/Election.java:226
if (!Objects.equals(metadata.myNodeId(), nodeId) && entry.getValue() != LEFT)
messaging.send(Message.out(Verb.TCM_ABORT_MIG, currentInitiator), metadata.directory.endpoint(nodeId));
}
}
else
{
throw new IllegalStateException("Current initiator [" + currentInitiator +"] does not match provided " + expectedInitiator +
" - run this command on a node where initialization has not yet been cleared, with the correct expected initiator");
}
}
public class PrepareHandler implements IVerbHandler<CMSInitializationRequest>
{
@Override
public void doVerb(Message<CMSInitializationRequest> message) throws IOException
{
logger.info("Received election initiation message {} from {}", message.payload, message.from());
if (!updateInitiator(null, message.payload.initiator))
throw new IllegalStateException(String.format("Got duplicate initiate migration message from %s, migration is already started by %s", message.from(), initiator()));
logger.info("Sending initiation response");
Directory initiatorDirectory = message.payload.directory;
TokenMap initiatorTokenMap = message.payload.tokenMap;
UUID initiatorSchemaVersion = message.payload.schemaVersion;
ClusterMetadata metadata = ClusterMetadata.current();
boolean match = true;
if (!initiatorDirectory.equals(metadata.directory))
{
match = false;
logger.warn("Initiator directory different from our");
initiatorDirectory.dumpDiff(metadata.directory);
}
if (!initiatorTokenMap.equals(metadata.tokenMap))
{
match = false;
logger.warn("Initiator tokenmap different from ours");
initiatorTokenMap.dumpDiff(metadata.tokenMap);View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Identify the winning initiator from the message text and let it complete the migration
- The losing node should catch this handler failure, run its abort() path, and stop its own candidacy
- Retry nomination only after the cluster returns to a quiescent (no-initiator) state
- Coordinate out-of-band so exactly one node initiates migration
Example fix
// before
// both A and B broadcast CMSInitializationRequest concurrently
// after
// catch and back off in initiate():
catch (IllegalStateException e) { logger.warn("Migration already started by " + Election.initiator()); abort(...); } Defensive patterns
Strategy: try-catch
Validate before calling
if (Election.initiator() != null && !Election.initiator().equals(thisInitiator)) { /* already started; skip sending CMSInitializationRequest */ } Try / catch
try { updateInitiator(null, payload.initiator); } catch (IllegalStateException e) { logger.warn("Duplicate initiation from {} ignored; started by {}", message.from(), initiator()); } Prevention
- Ensure only one node broadcasts CMSInitializationRequest per migration
- Make initiates idempotent: dedupe retries by initiator identity
- Have losing candidates abort cleanly and stop candidacy
When it happens
Trigger: Two nodes send CMSInitializationRequest nearly simultaneously; or a node retries its initiate and the first request already registered the initiator on this peer.
Common situations: Split-brain operator actions during CMS election; message retries/re-delivery after a slow first attempt; multiple nodes configured to self-nominate at startup at the same time.
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
- Migration already initiated by
- Unknown endpoint %s
- Can only initialize cluster identifier during epoch %d, but
- Failed to find first CMS node in directory
- Core cluster metadata objects should be addressed directly,
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/734b42e766f6159c.
Report an issue: GitHub.