apache/cassandra · error · IllegalStateException

Can't finish migration, initiator=

Error message

Can't finish migration, initiator=

What it means

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.

Solutions

  1. Inspect logs to identify the actual recorded initiator and let that node drive migration to completion
  2. Run abortInitialization with the correct expected initiator to clear stale state, then nominateSelf again
  3. Ensure only one operator executes the migration command at a time
  4. Retry after state is cleared; verify initiator() is null before initiating

Example fix

// before
// concurrent nominateSelf on two nodes -> finish() sees foreign initiator
// after
// single coordinator:
if (!updateInitiator(null, FBUtilities.getBroadcastAddressAndPort()))
    throw new IllegalStateException("already initiated by " + initiator.get());
Defensive patterns

Strategy: try-catch

Validate before calling

Object current = Election.initiator(); if (current != null && current != MIGRATING && !current.equals(self)) throw new IllegalStateException("Foreign initiator: " + current);

Try / catch

try { nominateSelf(...); } catch (IllegalStateException e) { // clear state via abortInitialization with the correct initiator, then retry }

Prevention

When it happens

Trigger: nominateSelf reaches finish() but the recorded initiator was concurrently changed (another node initiated, or a prior aborted attempt left an unexpected initiator value).

Common situations: Concurrent migration attempts from two nodes; a retried nominateSelf after a partially completed earlier run; state not reset after abort().

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/a71f3315edcb935a. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/tcm/migration/Election.java:163

                throw new IllegalStateException(msg);
            }
        }
    }

    private void finish(Set<InetAddressAndPort> sendTo)
    {
        CMSInitializationRequest.Initiator currentInitiator = initiator.get();
        if (currentInitiator != null &&
            Objects.equals(currentInitiator.endpoint, FBUtilities.getBroadcastAddressAndPort()) &&
            initiator.compareAndSet(currentInitiator, MIGRATING))
        {
            Startup.initializeAsFirstCMSNode();
            updateInitiator(MIGRATING, MIGRATED);
            MessageDelivery.fanoutAndWait(messaging, sendTo, Verb.TCM_NOTIFY_REQ, DistributedMetadataLogKeyspace.getLogState(Epoch.EMPTY, false));
        }
        else
        {
            throw new IllegalStateException("Can't finish migration, initiator="+currentInitiator);
        }
    }

    private void abort(CMSInitializationRequest.Initiator init, Set<InetAddressAndPort> sendTo)
    {
        logger.info("Aborting migration");
        CMSInitializationRequest.Initiator previous = initiator.getAndSet(null);
        logger.info("Reset local initiator state (was {}), sending abort message to peers", previous);
        for (InetAddressAndPort ep : sendTo)
            messaging.send(Message.out(Verb.TCM_ABORT_MIG, init), ep);
    }

    public CMSInitializationRequest.Initiator initiator()
    {
        return initiator.get();
    }

    public void migrated()

View on GitHub (pinned to 88fd0f6a0e)