{"record":{"id":"a71f3315edcb935a","repo":"apache/cassandra","slug":"can-t-finish-migration-initiator","errorCode":null,"errorMessage":"Can't finish migration, initiator=","messagePattern":"Can't finish migration, initiator=","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/tcm/migration/Election.java","lineNumber":163,"sourceCode":"                throw new IllegalStateException(msg);\n            }\n        }\n    }\n\n    private void finish(Set<InetAddressAndPort> sendTo)\n    {\n        CMSInitializationRequest.Initiator currentInitiator = initiator.get();\n        if (currentInitiator != null &&\n            Objects.equals(currentInitiator.endpoint, FBUtilities.getBroadcastAddressAndPort()) &&\n            initiator.compareAndSet(currentInitiator, MIGRATING))\n        {\n            Startup.initializeAsFirstCMSNode();\n            updateInitiator(MIGRATING, MIGRATED);\n            MessageDelivery.fanoutAndWait(messaging, sendTo, Verb.TCM_NOTIFY_REQ, DistributedMetadataLogKeyspace.getLogState(Epoch.EMPTY, false));\n        }\n        else\n        {\n            throw new IllegalStateException(\"Can't finish migration, initiator=\"+currentInitiator);\n        }\n    }\n\n    private void abort(CMSInitializationRequest.Initiator init, Set<InetAddressAndPort> sendTo)\n    {\n        logger.info(\"Aborting migration\");\n        CMSInitializationRequest.Initiator previous = initiator.getAndSet(null);\n        logger.info(\"Reset local initiator state (was {}), sending abort message to peers\", previous);\n        for (InetAddressAndPort ep : sendTo)\n            messaging.send(Message.out(Verb.TCM_ABORT_MIG, init), ep);\n    }\n\n    public CMSInitializationRequest.Initiator initiator()\n    {\n        return initiator.get();\n    }\n\n    public void migrated()","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/tcm/migration/Election.java#L145-L181","documentation":"Election.finish finalizes CMS migration by transitioning the initiator state. If the recorded initiator is neither this node's successful chain nor in the expected MIGRATING state (currentInitiator is stale or belongs to someone else), finish() throws IllegalStateException, leaving migration incomplete.","triggerScenarios":"nominateSelf reaches finish() but the recorded initiator was concurrently changed (another node initiated, or a prior aborted attempt left an unexpected initiator value).","commonSituations":"Concurrent migration attempts from two nodes; a retried nominateSelf after a partially completed earlier run; state not reset after abort().","solutions":["Inspect logs to identify the actual recorded initiator and let that node drive migration to completion","Run abortInitialization with the correct expected initiator to clear stale state, then nominateSelf again","Ensure only one operator executes the migration command at a time","Retry after state is cleared; verify initiator() is null before initiating"],"exampleFix":"// before\n// concurrent nominateSelf on two nodes -> finish() sees foreign initiator\n// after\n// single coordinator:\nif (!updateInitiator(null, FBUtilities.getBroadcastAddressAndPort()))\n    throw new IllegalStateException(\"already initiated by \" + initiator.get());","handlingStrategy":"try-catch","validationCode":"Object current = Election.initiator(); if (current != null && current != MIGRATING && !current.equals(self)) throw new IllegalStateException(\"Foreign initiator: \" + current);","typeGuard":null,"tryCatchPattern":"try { nominateSelf(...); } catch (IllegalStateException e) { // clear state via abortInitialization with the correct initiator, then retry }","preventionTips":["Serialize migration attempts: one initiator at a time","Clear initiator state (abortInitialization) after aborted runs","Confirm initiator() is null before starting a new migration"],"tags":["cassandra","tcm","state-machine"],"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-17T15:17:12.973Z"}