apache/cassandra · error · MarshalException

Only complex cells should have a cell path

Error message

Only complex cells should have a cell path

What it means

Cassandra throws this MarshalException when deserializing/validating a cell that carries a CellPath (the per-cell component used by collections, UDTs and other multi-cell/complex types) but the column itself is not complex (single-cell). Only complex columns can have path components, so a path on a simple column indicates corrupt or malformed data.

Solutions

  1. Verify the column definition matches the data being read (a frozen column must not receive cells with paths); unfreeze/keep the column multi-cell if path-carrying data must be read.
  2. Run nodetool scrub / repairs on the affected table to drop or rewrite corrupt cells.
  3. If triggered by an ALTER, ensure the column was altered consistently on all nodes and migrate data with INSERT after the schema change instead of reading stale cells.
  4. If you construct cells programmatically (internal tooling), only set a CellPath for isComplex() columns.

Example fix

// before (writing a cell with a path for a frozen column)
Cell<Object> cell = BufferCell.live(column, ts, value, CellPath.create(b));
// after
Cell<Object> cell = column.isComplex()
    ? BufferCell.live(column, ts, value, CellPath.create(b))
    : BufferCell.live(column, ts, value);
Defensive patterns

Strategy: validation

Validate before calling

if (!column.isComplex() && cell.path() != null)
    throw new IllegalArgumentException("Cell path set for non-complex column " + column.name);

Type guard

boolean canHavePath(ColumnMetadata col) { return col.isComplex(); }

Try / catch

try { /* deserialize/validate */ } catch (MarshalException e) {
    logger.error("Corrupt cell for {}: {}", column.name, e.getMessage());
    // trigger repair/scrub of the affected range
}

Prevention

When it happens

Trigger: ColumnMetadata.validateCell() calls validateCellPath() with a non-null CellPath while isComplex() is false — e.g. deserializing a partition containing a cell with a path for a frozen/single-cell column, or after altering a column from a non-frozen collection to frozen (making it single-cell) while old cells with paths still exist.

Common situations: Reading SSTables or receiving mutations written before an ALTER TYPE / frozen conversion; hand-crafted or corrupted commit log/mutation data; schema changes that changed a column's cell kind without rewriting existing data.

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


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

Appendix: source

Thrown at src/java/org/apache/cassandra/schema/ColumnMetadata.java:683

        }
        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)
    {
        if (!isComplex())
            throw new MarshalException("Only complex cells should have a cell path");

        assert type.isMultiCell();
        if (type.isCollection())
            ((CollectionType)type).nameComparator().validate(path.get(0));
        else
            ((UserType)type).nameComparator().validate(path.get(0));
    }

    public void appendCqlTo(CqlBuilder builder)
    {
        builder.append(name)
               .append(' ')
               .append(type);

        if (isStatic())
            builder.append(" static");

        if (isMasked())

View on GitHub (pinned to 88fd0f6a0e)