apache/cassandra · error · IllegalStateException

Bootstrap can be started exactly once, but seems to have alr

Error message

Bootstrap can be started exactly once, but seems to have already started: 

What it means

Thrown by StorageService.bootstrap when bootstrap is invoked while a bootstrap is already in progress. An AtomicReference (ongoingBootstrap) is populated via compareAndSet exactly once per process; if it is non-null a second concurrent bootstrap attempt fails, and the exception message includes the already-registered BootStrapper. Bootstrapping a node twice concurrently would corrupt streaming and token ownership, so it is a hard lifecycle invariant.

Source

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

        return DatabaseDescriptor.isIncrementalBackupsEnabled();
    }

    public void setIncrementalBackupsEnabled(boolean value)
    {
        DatabaseDescriptor.setIncrementalBackupsEnabled(value);
    }

    public Future<StreamState> startBootstrap(ClusterMetadata metadata,
                                              InetAddressAndPort beingReplaced,
                                              MovementMap movements,
                                              MovementMap strictMovements)
    {
        logger.info("Starting to bootstrap...");
        SystemKeyspace.setBootstrapState(SystemKeyspace.BootstrapState.IN_PROGRESS);
        BootStrapper bootstrapper = new BootStrapper(getBroadcastAddressAndPort(), metadata, movements, strictMovements);
        boolean res = ongoingBootstrap.compareAndSet(null, bootstrapper);
        if (!res)
            throw new IllegalStateException("Bootstrap can be started exactly once, but seems to have already started: " + bootstrapper);
        bootstrapper.addProgressListener(progressSupport);
        return bootstrapper.bootstrap(streamStateStore,
                                      useStrictConsistency && beingReplaced == null,
                                      beingReplaced); // handles token update
    }

    public void clearOngoingBootstrap()
    {
        ongoingBootstrap.set(null);
    }

    public void invalidateLocalRanges()
    {
        for (Keyspace keyspace : Keyspace.all())
        {
            for (ColumnFamilyStore cfs : keyspace.getColumnFamilyStores())
            {
                for (final ColumnFamilyStore store : cfs.concatWithIndexes())

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Wait for the running bootstrap to finish (monitor streaming progress via nodetool netstats) before considering a new bootstrap
  2. Restart the node process if bootstrap is wedged — the ongoingBootstrap state is in-memory and cleared on restart
  3. Serialize bootstrap invocation: check SystemKeyspace bootstrap state (or an external coordination flag) before calling bootstrap()
  4. Do not retry bootstrap on timeout; inspect logs to confirm the first attempt actually failed before retrying

Example fix

// before
new Thread(() -> ss.bootstrap()).start();
ss.bootstrap(); // IllegalStateException: already started
// after
if (SystemKeyspace.getBootstrapState() != SystemKeyspace.BootstrapState.IN_PROGRESS)
    ss.bootstrap();
else
    logger.info("Bootstrap already in progress; skipping");
Defensive patterns

Strategy: try-catch

Validate before calling

if (SystemKeyspace.getBootstrapState() == SystemKeyspace.BootstrapState.IN_PROGRESS)
    throw new IllegalStateException("Bootstrap already in progress");
ss.bootstrap();

Try / catch

try { ss.bootstrap(); } catch (IllegalStateException e) { if (e.getMessage().contains("already started")) logger.info("Bootstrap already running; joining existing bootstrap"); else throw e; }

Prevention

When it happens

Trigger: Calling bootstrap() (directly or via the StorageService JMX/startup path) a second time while the first bootstrap is still running; concurrent tooling or scripts double-invoking the bootstrap operation; retry logic re-triggering bootstrap after a slow start without checking completion.

Common situations: Operations automation that retried node startup because the first attempt appeared hung during streaming; monitoring scripts calling the bootstrap JMX operation in parallel; code changes that invoke bootstrap from two lifecycle hooks during the same process lifetime.

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