apache/cassandra · error · RuntimeException

Cannot snapshot until bootstrap completes

Error message

Cannot snapshot until bootstrap completes

What it means

TakeSnapshotTask.getSnapshotsToCreate refuses to take snapshots while the node's StorageService operation mode is JOINING, throwing RuntimeException. During bootstrap the node is still streaming token ranges and its data is incomplete/in-flux, so a snapshot would not represent consistent, fully-owned data. This check was deliberately placed in getSnapshotsToCreate (not the builder) so the mode is evaluated as late as possible, right before the snapshot executes.

Source

Thrown at src/java/org/apache/cassandra/service/snapshot/TakeSnapshotTask.java:80

    private String snapshotName;
    private final Map<ColumnFamilyStore, TableSnapshot> snapshotsToCreate = new HashMap<>();

    public TakeSnapshotTask(SnapshotManager manager, SnapshotOptions options)
    {
        super(options);
        this.manager = manager;
    }

    @Override
    public SnapshotTaskType getTaskType()
    {
        return SnapshotTaskType.SNAPSHOT;
    }

    public Map<ColumnFamilyStore, TableSnapshot> getSnapshotsToCreate()
    {
        if (StorageService.instance.operationMode() == StorageService.Mode.JOINING)
            throw new RuntimeException("Cannot snapshot until bootstrap completes");

        // This is not in builder's build method on purpose in order to postpone the timestamp for as long as possible
        // until the actual snapshot is taken. If we constructed a task and have not done anything with it for 5 minutes
        // then by the time a snapshot would be taken the creation time would be quite off
        Instant creationTimeInOptions = options.creationTime;
        if (creationTimeInOptions == null)
            creationTime = Instant.ofEpochMilli(Clock.Global.currentTimeMillis());
        else
            creationTime = options.creationTime;

        snapshotName = SnapshotOptions.getSnapshotName(options.type, options.tag, creationTime);

        Set<ColumnFamilyStore> entitiesForSnapshot = options.cfs == null ? parseEntitiesForSnapshot(options.entities) : Set.of(options.cfs);

        for (ColumnFamilyStore cfs : entitiesForSnapshot)
        {
            Set<File> snapshotDirs = cfs.getDirectories().getSnapshotDirsWithoutCreation(snapshotName);

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Wait until the node finishes joining (nodetool status shows UN, or operationMode is NORMAL) before snapshotting.
  2. Add automation guards that check nodetool info / StorageService mode and defer the snapshot until bootstrap completes.
  3. Retry the snapshot after bootstrap; nothing is corrupted by the earlier failure.

Example fix

// before
nodetool snapshot -t backup   # immediately after restart/join
// after
until nodetool info | grep -q 'Mode: NORMAL'; do sleep 30; done
nodetool snapshot -t backup
Defensive patterns

Strategy: retry

Validate before calling

if (StorageService.instance.operationMode() == StorageService.Mode.JOINING)
    throw new IllegalStateException("Node still joining; postpone snapshot");

Try / catch

try { takeSnapshot(); } catch (RuntimeException e) { if (e.getMessage().contains("bootstrap")) { waitUntilNormal(); takeSnapshot(); } else throw e; }

Prevention

When it happens

Trigger: Running nodetool snapshot while the node is still bootstrapping into the cluster (operationMode() == JOINING); automation that fires snapshots immediately after node start before bootstrap completes.

Common situations: Backup cron jobs that start when the node process is up but before join completes; large bootstraps (big data streaming) overlapping scheduled snapshot windows; monitoring scripts snapshotting new nodes too early.

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