apache/cassandra · error · IllegalStateException

can not take ephemeral snapshot

Error message

can not take ephemeral snapshot (%s) while ttl is specified too

What it means

validateTTL rejects combining an ephemeral snapshot with an explicit ttl, throwing IllegalStateException. Ephemeral snapshots are transient by definition (deleted as soon as their session ends), so attaching a TTL is contradictory. The two options are mutually exclusive at the builder level.

Solutions

  1. Remove the --ttl flag when taking an ephemeral snapshot.
  2. If TTL-based retention is needed, take a regular (non-ephemeral) snapshot with a ttl instead.
  3. Update wrapper scripts so ephemeral and ttl options are mutually exclusive.

Example fix

// before
nodetool snapshot --ephemeral -t tmp --ttl 10m
// after
nodetool snapshot --ephemeral -t tmp
Defensive patterns

Strategy: validation

Validate before calling

if (ephemeral && ttl != null) throw new IllegalArgumentException("ephemeral snapshots cannot specify ttl");

Try / catch

try { takeSnapshot(opts); } catch (IllegalStateException e) { if (e.getMessage().contains("ephemeral")) takeSnapshot(opts.withoutTtl()); else throw e; }

Prevention

When it happens

Trigger: nodetool snapshot --ephemeral --ttl 10m, or SnapshotOptions.builder().ephemeral(true).withTTL(...) — any call where both ephemeral=true and ttl != null reach build().

Common situations: Tooling that always sets a default TTL but was switched to ephemeral snapshots; users combining flags assuming TTL governs cleanup of ephemeral snapshots; script parameter merge accidentally passing both.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/71dc202a601221e2. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/service/snapshot/SnapshotOptions.java:273

            if (!SAFE_SNAPSHOT_NAME.matcher(resolvedSnapshotName).matches())
            {
                throw new IllegalArgumentException("Snapshot name contains illegal characters: " + resolvedSnapshotName + ". " +
                                                   "Allowed characters must match the pattern: " + SAFE_SNAPSHOT_NAME.pattern() +
                                                   " with a maximum of length of " + FILENAME_LENGTH + " characters.");
            }
        }

        private void validateTTL(boolean ephemeral, DurationSpec.IntSecondsBound ttl)
        {
            if (ttl != null)
            {
                int minAllowedTtlSecs = CassandraRelevantProperties.SNAPSHOT_MIN_ALLOWED_TTL_SECONDS.getInt();
                if (ttl.toSeconds() < minAllowedTtlSecs)
                    throw new IllegalArgumentException(format("ttl for snapshot must be at least %d seconds", minAllowedTtlSecs));
            }

            if (ephemeral && ttl != null)
                throw new IllegalStateException(format("can not take ephemeral snapshot (%s) while ttl is specified too", tag));
        }
    }

    @Override
    public String toString()
    {
        return "CreateSnapshotOptions{" +
               "type=" + type +
               ", tag='" + tag + '\'' +
               ", ttl=" + ttl +
               ", creationTime=" + creationTime +
               ", skipFlush=" + skipFlush +
               ", ephemeral=" + ephemeral +
               ", entities=" + Arrays.toString(entities) +
               '}';
    }
}

View on GitHub (pinned to 88fd0f6a0e)