{"record":{"id":"734b42e766f6159c","repo":"apache/cassandra","slug":"got-duplicate-initiate-migration-message-from-s","errorCode":null,"errorMessage":"Got duplicate initiate migration message from %s, migration is already started by %s","messagePattern":"Got duplicate initiate migration message from (.+?), migration is already started by (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/tcm/migration/Election.java","lineNumber":226,"sourceCode":"                if (!Objects.equals(metadata.myNodeId(), nodeId) && entry.getValue() != LEFT)\n                    messaging.send(Message.out(Verb.TCM_ABORT_MIG, currentInitiator), metadata.directory.endpoint(nodeId));\n            }\n        }\n        else\n        {\n            throw new IllegalStateException(\"Current initiator [\" + currentInitiator +\"] does not match provided \" + expectedInitiator +\n                                            \" - run this command on a node where initialization has not yet been cleared, with the correct expected initiator\");\n        }\n    }\n\n    public class PrepareHandler implements IVerbHandler<CMSInitializationRequest>\n    {\n        @Override\n        public void doVerb(Message<CMSInitializationRequest> message) throws IOException\n        {\n            logger.info(\"Received election initiation message {} from {}\", message.payload, message.from());\n            if (!updateInitiator(null, message.payload.initiator))\n                throw new IllegalStateException(String.format(\"Got duplicate initiate migration message from %s, migration is already started by %s\", message.from(), initiator()));\n\n            logger.info(\"Sending initiation response\");\n            Directory initiatorDirectory = message.payload.directory;\n            TokenMap initiatorTokenMap = message.payload.tokenMap;\n            UUID initiatorSchemaVersion = message.payload.schemaVersion;\n            ClusterMetadata metadata = ClusterMetadata.current();\n            boolean match = true;\n            if (!initiatorDirectory.equals(metadata.directory))\n            {\n                match = false;\n                logger.warn(\"Initiator directory different from our\");\n                initiatorDirectory.dumpDiff(metadata.directory);\n            }\n            if (!initiatorTokenMap.equals(metadata.tokenMap))\n            {\n                match = false;\n                logger.warn(\"Initiator tokenmap different from ours\");\n                initiatorTokenMap.dumpDiff(metadata.tokenMap);","sourceCodeStart":208,"sourceCodeEnd":244,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/tcm/migration/Election.java#L208-L244","documentation":"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.","triggerScenarios":"Two nodes send CMSInitializationRequest nearly simultaneously; or a node retries its initiate and the first request already registered the initiator on this peer.","commonSituations":"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.","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"],"exampleFix":"// before\n// both A and B broadcast CMSInitializationRequest concurrently\n// after\n// catch and back off in initiate():\ncatch (IllegalStateException e) { logger.warn(\"Migration already started by \" + Election.initiator()); abort(...); }","handlingStrategy":"try-catch","validationCode":"if (Election.initiator() != null && !Election.initiator().equals(thisInitiator)) { /* already started; skip sending CMSInitializationRequest */ }","typeGuard":null,"tryCatchPattern":"try { updateInitiator(null, payload.initiator); } catch (IllegalStateException e) { logger.warn(\"Duplicate initiation from {} ignored; started by {}\", message.from(), initiator()); }","preventionTips":["Ensure only one node broadcasts CMSInitializationRequest per migration","Make initiates idempotent: dedupe retries by initiator identity","Have losing candidates abort cleanly and stop candidacy"],"tags":["cassandra","tcm","concurrency"],"backgroundTag":"invalid-state-transition","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}