apache/cassandra · error · MarshalException
A TTL should not be negative
Error message
A TTL should not be negative
What it means
ExpiringLivenessInfo (LivenessInfo.Expiring) validates its fields on construction/deserialization: a negative TTL is illegal because TTLs are non-negative durations in seconds. MarshalException is thrown to reject corrupt or invalid expiration data before it enters the read/write path.
Source
Thrown at src/java/org/apache/cassandra/db/LivenessInfo.java:334
}
@Override
public void digest(Digest digest)
{
super.digest(digest);
// As of 5.0, local expiration times are encoded as unsigned integers on disk, so we can do the
// same thing here to populate the digest. This supports extended TTLs, but also maintains digest
// compatibility with previous versions, avoiding false digest mismatches during upgrades.
digest.updateWithInt(Cell.deletionTimeLongToUnsignedInteger(localExpirationTime));
digest.updateWithInt(ttl);
}
@Override
public void validate()
{
if (ttl < 0)
throw new MarshalException("A TTL should not be negative");
if (localExpirationTime < 0)
throw new MarshalException("A local expiration time should not be negative");
}
@Override
public int dataSize()
{
return super.dataSize()
+ TypeSizes.sizeof(ttl)
+ TypeSizes.sizeof(localExpirationTime);
}
@Override
public LivenessInfo withUpdatedTimestamp(long newTimestamp)
{
return new ExpiringLivenessInfo(newTimestamp, ttl, localExpirationTime);
}View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Clamp or validate TTL before writing: reject or floor negative computed values to 0 (no expiration).
- Fix the source arithmetic (e.g. deadline - now) and guard against clock skew.
- If it appears during reads without negative writes, run a repair/scrub — the data may be corrupt.
Example fix
// before
int ttl = (int) ((expiryAt - System.currentTimeMillis()) / 1000); // can be negative
session.execute("INSERT INTO t(k,v) VALUES(?,?,?) USING TTL ?", k, v, ttl);
// after
int ttl = Math.max(0, (int) ((expiryAt - System.currentTimeMillis()) / 1000));
session.execute("INSERT INTO t(k,v) VALUES(?,?,?) USING TTL ?", k, v, ttl); Defensive patterns
Strategy: validation
Validate before calling
if (ttl < 0) throw new IllegalArgumentException("TTL must be >= 0, got " + ttl); Type guard
int safeTtl(long computedTtl) { return (int) Math.max(0, computedTtl); } Try / catch
try { session.execute(stmt); } catch (InvalidQueryException e) { if (e.getMessage().contains("TTL")) { fixTtlAndRetry(); } else throw e; } Prevention
- Clamp computed TTLs with Math.max(0, ttl) before binding.
- Validate user-supplied TTLs at the API boundary.
- Account for clock skew when deriving TTL from timestamps.
When it happens
Trigger: Writing a cell with a negative TTL (e.g. INSERT ... USING TTL -1); deserializing corrupt SSTable or mutation data where the TTL field is negative; passing a computed TTL expression that underflows to negative.
Common situations: Application computes TTL from a timestamp difference that came out negative (clock skew or expired deadline); drivers accepting client-supplied TTL values without validation; corrupted data files.
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 local expiration time should not be negative
- A TTL should not be negative
- %s must be positive value <= %dB, but was %dB
- Too many bytes for comparator
- Invalid Timestamp:
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/d3d0d6083abfd2c6.
Report an issue: GitHub.