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

  1. Identify the winning initiator from the message text and let it complete the migration
  2. The losing node should catch this handler failure, run its abort() path, and stop its own candidacy
  3. Retry nomination only after the cluster returns to a quiescent (no-initiator) state
  4. 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

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


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/734b42e766f6159c. Report an issue: GitHub.