apache/cassandra · error · MarshalException
A tombstone should not have a value
Error message
A tombstone should not have a value
What it means
ColumnMetadata.validateCell() enforces that a Cell representing a tombstone (liveness deletion info present) carries an empty value. A tombstone whose serialized value size is greater than zero indicates corrupted or invalidly written data, so MarshalException is thrown during validation.
Source
Thrown at src/java/org/apache/cassandra/schema/ColumnMetadata.java:662
}
public boolean isSimple()
{
return !isComplex();
}
public CellPath.Serializer cellPathSerializer()
{
// Collections are our only complex so far, so keep it simple
return CollectionType.cellPathSerializer;
}
public <V> void validateCell(Cell<V> cell)
{
if (cell.isTombstone())
{
if (cell.valueSize() > 0)
throw new MarshalException("A tombstone should not have a value");
if (cell.path() != null)
validateCellPath(cell.path());
}
else if(type.isUDT())
{
// To validate a non-frozen UDT field, both the path and the value
// are needed, the path being an index into an array of value types.
((UserType)type).validateCell(cell);
}
else
{
type.validateCellValue(cell.value(), cell.accessor());
if (cell.path() != null)
validateCellPath(cell.path());
}
}
private void validateCellPath(CellPath path)View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Run nodetool scrub on the affected table to drop corrupt cells
- Restore the affected SSTables/backups or run repair to obtain clean copies from healthy replicas
- Check cluster version consistency and client write paths that build Cells directly; re-produce with a repro test if writing via internal APIs
Example fix
// before (internal API misuse)
Cell<v> bad = BufferCell.live(column, ts, value, del("2024-01-01T00:00:00Z"));
// after
Cell<v> ok = BufferCell.tombstone(column.deletionTime(), ts, path); // empty value for tombstones Defensive patterns
Strategy: try-catch
Validate before calling
// before reading/partition processing
if (cell.isTombstone() && cell.valueSize() > 0) {
log.warn("Skipping tombstone with value on column " + column.name);
return;
} Type guard
boolean isWellFormedTombstone(Cell<?> c) { return c.isTombstone() && c.valueSize() == 0; } Try / catch
try { metadata.validateCell(cell); } catch (MarshalException e) { log.error("Invalid cell: {}", e.getMessage()); /* quarantine partition, run scrub/repair */ } Prevention
- Never construct tombstone cells with a non-empty value via internal APIs
- Run nodetool scrub/verify periodically to catch corrupt SSTables early
- Keep cluster nodes on compatible versions during rolling upgrades
- Verify checksums and disk health after unclean shutdowns before replaying data
When it happens
Trigger: Reading or writing a partition where a cell is marked as a tombstone but has a non-empty value — typically from corrupt SSTables, a coordinator/replica version or serialization bug, or hand-crafted mutation data via internal APIs.
Common situations: During compaction/validation reads after a crash or corrupted commit log; replaying WAL/mutation data produced by a buggy client using the internal API; after upgrading across versions with a serialization change.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Cannot DROP COMPACT STORAGE as some nodes in the cluster (%s
- Not enough space to write %s to %s (%s available)
- Not enough disk space to store %s
- Not enough bytes to header of the comparator part of compone
- Not enough bytes to read comparator name of component %s
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/80b3e5f4e0ae0b2f.
Report an issue: GitHub.