{"record":{"id":"ddba71b0a2726ce8","repo":"apache/cassandra","slug":"bootstrap-can-be-started-exactly-once-but-seems-t","errorCode":null,"errorMessage":"Bootstrap can be started exactly once, but seems to have already started: ","messagePattern":"Bootstrap can be started exactly once, but seems to have already started: ","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/service/StorageService.java","lineNumber":1605,"sourceCode":"        return DatabaseDescriptor.isIncrementalBackupsEnabled();\n    }\n\n    public void setIncrementalBackupsEnabled(boolean value)\n    {\n        DatabaseDescriptor.setIncrementalBackupsEnabled(value);\n    }\n\n    public Future<StreamState> startBootstrap(ClusterMetadata metadata,\n                                              InetAddressAndPort beingReplaced,\n                                              MovementMap movements,\n                                              MovementMap strictMovements)\n    {\n        logger.info(\"Starting to bootstrap...\");\n        SystemKeyspace.setBootstrapState(SystemKeyspace.BootstrapState.IN_PROGRESS);\n        BootStrapper bootstrapper = new BootStrapper(getBroadcastAddressAndPort(), metadata, movements, strictMovements);\n        boolean res = ongoingBootstrap.compareAndSet(null, bootstrapper);\n        if (!res)\n            throw new IllegalStateException(\"Bootstrap can be started exactly once, but seems to have already started: \" + bootstrapper);\n        bootstrapper.addProgressListener(progressSupport);\n        return bootstrapper.bootstrap(streamStateStore,\n                                      useStrictConsistency && beingReplaced == null,\n                                      beingReplaced); // handles token update\n    }\n\n    public void clearOngoingBootstrap()\n    {\n        ongoingBootstrap.set(null);\n    }\n\n    public void invalidateLocalRanges()\n    {\n        for (Keyspace keyspace : Keyspace.all())\n        {\n            for (ColumnFamilyStore cfs : keyspace.getColumnFamilyStores())\n            {\n                for (final ColumnFamilyStore store : cfs.concatWithIndexes())","sourceCodeStart":1587,"sourceCodeEnd":1623,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/service/StorageService.java#L1587-L1623","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nnew Thread(() -> ss.bootstrap()).start();\nss.bootstrap(); // IllegalStateException: already started\n// after\nif (SystemKeyspace.getBootstrapState() != SystemKeyspace.BootstrapState.IN_PROGRESS)\n    ss.bootstrap();\nelse\n    logger.info(\"Bootstrap already in progress; skipping\");","handlingStrategy":"try-catch","validationCode":"if (SystemKeyspace.getBootstrapState() == SystemKeyspace.BootstrapState.IN_PROGRESS)\n    throw new IllegalStateException(\"Bootstrap already in progress\");\nss.bootstrap();","typeGuard":null,"tryCatchPattern":"try { ss.bootstrap(); } catch (IllegalStateException e) { if (e.getMessage().contains(\"already started\")) logger.info(\"Bootstrap already running; joining existing bootstrap\"); else throw e; }","preventionTips":["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"],"tags":["lifecycle","bootstrap","concurrency","state"],"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-14T11:17:12.474Z"}