apache/cassandra · error · MarshalException
A TTL should not be negative
Error message
A TTL should not be negative
What it means
AbstractCell.validate() checks a cell's invariants when it is written or read back. A negative TTL can never be produced by a correct writer, so a negative value means corrupted data on disk, a bad serialization, or a bug in a custom cell implementation. The cell is rejected with a MarshalException rather than propagating invalid data.
Source
Thrown at src/java/org/apache/cassandra/db/rows/AbstractCell.java:189
public void digest(Digest digest)
{
if (isCounterCell())
digest.updateWithCounterContext(value(), accessor());
else
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;View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Run `nodetool scrub` on the affected table to drop corrupt cells.
- Restore the affected data from backups/snapshots.
- Check disk/filesystem health (smartctl, fsck) for silent corruption.
- File/inspect the writer path: verify no custom code produces negative TTLs.
Example fix
// before: writing with unvalidated ttl
long ttl = computeTtl(request);
cell = cf.cell(column, ts, (int) ttl, ldt, value);
// after
int ttl = computeTtl(request);
if (ttl < 0) throw new IllegalArgumentException("TTL must be >= 0"); Defensive patterns
Strategy: validation
Validate before calling
if (cell.ttl() < 0) throw new IllegalArgumentException("negative TTL before write"); Type guard
boolean hasValidTtl(AbstractCell<?> c) { return c.ttl() >= 0; } Try / catch
try { row.validate(); } catch (MarshalException e) { quarantineCorruptRow(rowKey); scrubTable(); } Prevention
- Always validate rows before persisting via custom writers
- Scrub after any disk failure or restore
- Keep TTL computation clamped to >= 0
When it happens
Trigger: Reading a cell whose serialized TTL field was corrupted or written by a buggy encoder; deserializing hand-crafted/mutated SSTable or mutation data; a custom IVersionedAsymmetricSerializer or cell factory that passes negative ttl values.
Common situations: Corrupt SSTables after hardware failure; third-party tools writing sstables directly; fuzzing/ingestion of malformed commitlog segments; downgrade/upgrade paths with format bugs.
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 local deletion time should not be negative
- Shoud not have a TTL without an associated local deletion ti
- A local deletion time should not be negative in '%s'
- A local expiration time should not be negative
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/079548e51aeb1ee3.
Report an issue: GitHub.