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

  1. Run nodetool scrub on the affected table to drop corrupt cells
  2. Restore the affected SSTables/backups or run repair to obtain clean copies from healthy replicas
  3. 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

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


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/80b3e5f4e0ae0b2f. Report an issue: GitHub.