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
- Wait for the running bootstrap to finish (monitor streaming progress via nodetool netstats) before considering a new bootstrap
- Restart the node process if bootstrap is wedged — the ongoingBootstrap state is in-memory and cleared on restart
- Serialize bootstrap invocation: check SystemKeyspace bootstrap state (or an external coordination flag) before calling bootstrap()
- 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
- Invoke bootstrap only once per node process lifetime, from a single code path
- Never blindly retry bootstrap after timeouts; check streaming state/netstats first
- Coordinate bootstrap via SystemKeyspace.BootstrapState before invoking
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
- 0x0000
- Node is still rebuilding. Check nodetool netstats.
- Transfer of stream %s already completed or aborted (perhaps
- SASL negotiation not complete
- Null MBeanServer
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/ddba71b0a2726ce8.
Report an issue: GitHub.