apache/cassandra · error · IllegalArgumentException
ttl for snapshot must be at least
Error message
ttl for snapshot must be at least %d seconds
What it means
validateTTL enforces a minimum TTL for snapshots, read from the SNAPSHOT_MIN_ALLOWED_TTL_SECONDS property. A snapshot created with a ttl smaller than this minimum is rejected with IllegalArgumentException, because very short TTLs would make TTL-based snapshot cleanup churn effectively useless. The ttl parameter is only checked when it is non-null (i.e. the caller requested a TTL-bound snapshot).
Solutions
- Increase the --ttl value to at least the configured minimum (default 60 seconds).
- Lower cassandra.snapshot.min_allowed_ttl_seconds in cassandra.yaml / -Dcassandra.snapshot.min_allowed_ttl_seconds if genuinely shorter TTLs are needed.
- Omit ttl entirely if the snapshot should be permanent.
Example fix
// before nodetool snapshot -t daily --ttl 10s // after nodetool snapshot -t daily --ttl 60s
Defensive patterns
Strategy: validation
Validate before calling
int minTtl = Integer.getInteger("cassandra.snapshot.min_allowed_ttl_seconds", 60);
if (ttlSeconds < minTtl) ttlSeconds = minTtl; // clamp before invoking Try / catch
try { snapshotWithTtl(ttl); } catch (IllegalArgumentException e) { if (e.getMessage().contains("at least")) retryWithTtl(minAllowedTtl); else throw e; } Prevention
- Read cassandra.snapshot.min_allowed_ttl_seconds from config before choosing ttl
- Use seconds consistently to avoid unit confusion
- Omit ttl for permanent snapshots
When it happens
Trigger: nodetool snapshot --ttl <small-duration> (e.g. --ttl 5s) or SnapshotOptions.builder().withTTL(DurationSpec.IntSecondsBound of a value below cassandra.snapshot.min_allowed_ttl_seconds, default 60).
Common situations: Users passing a small ttl expecting a short-lived snapshot for quick testing; scripts with unit confusion (seconds vs milliseconds); clusters where the min TTL property was raised but tooling still uses old values.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- A TTL should not be negative
- A TTL should not be negative
- can not take ephemeral snapshot
- Invalid throttle for snapshot_links_per_second: must be…
- Shoud not have a TTL without an associated local deletion…
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/2a323644dd9df8fe.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/service/snapshot/SnapshotOptions.java:269
// snapshot names via version build metadata (e.g. an upgrade snapshot "<millis>-upgrade-5.0.4+build-...").
// The remaining S3-safe characters (! * ' ( )) are intentionally excluded as they are
// shell-significant and error-prone in paths, and the path separator '/' is excluded too,
// which is what blocks traversal attempts such as "../../mysnapshot"
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)