apache/cassandra · error · MarshalException
Shoud not have a TTL without an associated local deletion ti
Error message
Shoud not have a TTL without an associated local deletion time
What it means
An expiring cell (a cell with a positive TTL) must also carry a valid localDeletionTime, since that timestamp determines when it expires into a tombstone. A TTL without localDeletionTime makes expiry undefined, so validate() rejects the cell with MarshalException. Note the message contains a typo ("Shoud") in the source.
Source
Thrown at src/java/org/apache/cassandra/db/rows/AbstractCell.java:195
digest.update(value(), accessor());
digest.updateWithLong(timestamp())
.updateWithInt(ttl())
.updateWithBoolean(isCounterCell());
if (path() != null)
path().digest(digest);
}
public void validate()
{
if (ttl() < 0)
throw new MarshalException("A TTL should not be negative");
if (localDeletionTime() < 0)
throw new MarshalException("A local deletion time should not be negative");
if (localDeletionTime() == INVALID_DELETION_TIME)
throw new MarshalException("A local deletion time should not be a legacy overflowed value");
if (isExpiring() && localDeletionTime() == NO_DELETION_TIME)
throw new MarshalException("Shoud not have a TTL without an associated local deletion time");
// non-frozen UDTs require both the cell path & value to validate,
// so that logic is pushed down into ColumnMetadata. Tombstone
// validation is done there too as it also involves the cell path
// for complex columns
column().validateCell(this);
}
public boolean hasInvalidDeletions()
{
if (ttl() < 0 || localDeletionTime() == INVALID_DELETION_TIME || localDeletionTime() < 0 || (isExpiring() && localDeletionTime() == NO_DELETION_TIME))
return true;
return false;
}
public long maxTimestamp()
{
return timestamp();View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Always set localDeletionTime together with TTL: use (now + ttl) in seconds when building cells.
- Scrub affected SSTables to drop invalid expiring cells.
- Restore affected data from backup.
- Fix any custom serializer so ttl<=0 implies NO_DELETION_TIME and ttl>0 implies a real deletion time.
Example fix
// before cell = factory.cell(col, ts, ttl, NO_DELETION_TIME, value, path); // after cell = factory.cell(col, ts, ttl, ttl > 0 ? (int)(nowSec + ttl) : NO_DELETION_TIME, value, path);
Defensive patterns
Strategy: validation
Validate before calling
if (ttl > 0 && ldt == NO_DELETION_TIME) throw new IllegalArgumentException("TTL requires localDeletionTime"); Type guard
boolean hasConsistentExpiry(AbstractCell<?> c) { return !c.isExpiring() || c.localDeletionTime() != NO_DELETION_TIME; } Try / catch
try { row.validate(); } catch (MarshalException e) { quarantineCorruptRow(e); } Prevention
- When constructing expiring cells always compute ldt = nowSeconds + ttl
- Unit-test custom cell factories against validate()
- Never persist cells built from partial deserialization
When it happens
Trigger: Deserializing a cell where ttl > 0 but localDeletionTime == NO_DELETION_TIME (corruption or buggy serializer); custom cell factories constructing expiring cells without setting the deletion time.
Common situations: Hand-written or third-party SSTable writers forgetting to set localDeletionTime; corrupted rows after disk issues; incorrectly implemented streaming/paxos payloads.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- A TTL should not be negative
- A local deletion time should not be negative
- A local deletion time should not be a legacy overflowed valu
- A local deletion time should not be negative in '%s'
- A TTL should not be negative
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/f9c0cc29a695f755.
Report an issue: GitHub.