apache/cassandra · error · IllegalStateException

Can not resume bootstrap as join sequence has not been start

Error message

Can not resume bootstrap as join sequence has not been started

What it means

Thrown by StorageService.resumeBootstrap when the node's current in-progress sequence in ClusterMetadata is neither a BootstrapAndJoin nor a BootstrapAndReplace. It means resumeBootstrap was invoked, but no bootstrap/join sequence was ever started (or it already finished and was cleaned up), so there is nothing to resume. Cassandra requires an actual in-flight multi-step operation persisted in ClusterMetadata before a bootstrap can be resumed.

Source

Thrown at src/java/org/apache/cassandra/service/StorageService.java:1038

                throw new IllegalStateException("Cannot join the ring until bootstrap completes");
            }
        }
        else if (isBootstrapMode())
        {
            // bootstrap is not complete hence node cannot join the ring
            logger.warn("Can't join the ring because bootstrap hasn't completed.");
            throw new IllegalStateException("Cannot join the ring until bootstrap completes");
        }
    }

    public void resumeBootstrapSequence()
    {
        ClusterMetadata metadata = ClusterMetadata.current();
        NodeId id = metadata.myNodeId();
        MultiStepOperation<?> sequence = metadata.inProgressSequences.get(id);

        if (!(sequence instanceof BootstrapAndJoin) && !(sequence instanceof BootstrapAndReplace))
            throw new IllegalStateException("Can not resume bootstrap as join sequence has not been started");
        clearOngoingBootstrap();
        InProgressSequences.finishInProgressSequences(id);
        // only start transports and report that we're done if the resumed bootstrap completed successfully
        // See CASSANDRA-16491
        if (ongoingBootstrap.get() == null)
        {
            if (!isNativeTransportRunning())
                daemon.initializeClientTransports();
            daemon.start();
            progressSupport.progress("bootstrap", new ProgressEvent(ProgressEventType.COMPLETE, 1, 1, "Resume bootstrap complete"));
            logger.info("Resume complete");
        }
    }

    public boolean readyToFinishJoiningRing()
    {
        ClusterMetadata metadata = ClusterMetadata.current();
        NodeId id = metadata.myNodeId();

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Verify the node actually has an in-flight bootstrap: check nodetool metadata / logs for a BootstrapAndJoin or BootstrapAndReplace sequence before calling resumebootstrap
  2. If bootstrap never started, just start the node normally (or run the bootstrap/replacement again) instead of resuming
  3. If the sequence is stuck in a bad state, cancel it (nodetool cancelhandoff / cancel the bootstrap per docs) and re-bootstrap from scratch
  4. If bootstrap already completed, no action is needed — the node is already joined; skip the resume step

Example fix

// before: blindly resuming
storageService.resumeBootstrap();

// after: only resume when a bootstrap sequence exists
ClusterMetadata md = ClusterMetadata.current();
MultiStepOperation<?> seq = md.inProgressSequences.get(md.myNodeId());
if (seq instanceof BootstrapAndJoin || seq instanceof BootstrapAndReplace)
    storageService.resumeBootstrap();
Defensive patterns

Strategy: validation

Validate before calling

ClusterMetadata md = ClusterMetadata.current();
MultiStepOperation<?> seq = md.inProgressSequences.get(md.myNodeId());
boolean canResume = seq instanceof BootstrapAndJoin || seq instanceof BootstrapAndReplace;
if (!canResume) throw new IllegalStateException("No bootstrap sequence in progress; start bootstrap instead of resuming");

Type guard

static boolean isBootstrapSequence(MultiStepOperation<?> seq) {
    return seq instanceof BootstrapAndJoin || seq instanceof BootstrapAndReplace;
}

Try / catch

try {
    storageService.resumeBootstrap();
} catch (IllegalStateException e) {
    if (e.getMessage().contains("join sequence has not been started")) {
        logger.warn("Nothing to resume; node is not mid-bootstrap", e);
    } else throw e;
}

Prevention

When it happens

Trigger: Calling nodetool resumebootstrap (or StorageService.resumeBootstrap()) on a node whose ClusterMetadata.inProgressSequences contains no BootstrapAndJoin/BootstrapAndReplace entry for its own NodeId — e.g. the node never started bootstrapping, bootstrap already completed, the sequence was cancelled, or the node was restarted after the sequence was removed.

Common situations: Operator runs resumebootstrap on a node that isn't actually stuck mid-bootstrap; running it on an already-bootstrapped node by mistake; running it after a failed bootstrap was cancelled and cleaned up; cluster metadata was reset or the node was decommissioned/re-added.

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