apache/cassandra · error · InvalidRequestException

List index out of bound, list has size

Error message

List index %d out of bound, list has size %d

What it means

Thrown when the index used in a list element assignment is outside the bounds of the existing list (negative, or >= current size). Lists in Cassandra are cell-indexed by their existing element paths; you can only overwrite existing positions, not grow via index.

Solutions

  1. Fetch the list first and validate 0 <= index < size before the indexed update
  2. Use list append (l = l + [...]) to grow, or rewrite the whole list, instead of out-of-range indexes
  3. Re-read the list after concurrent mutations before computing the index

Example fix

// before
int idx = list.size(); // off-by-one, out of bounds
UPDATE t SET l[idx] = 'v';
// after
int idx = list.size() - 1;
if (idx >= 0) UPDATE t SET l[idx] = 'v';
Defensive patterns

Strategy: validation

Validate before calling

List<String> l = row.getList("l", String.class); if (idx < 0 || idx >= l.size()) throw new IndexOutOfBoundsException("idx=" + idx + " size=" + l.size());

Try / catch

try { session.execute(stmt); } catch (InvalidQueryException e) { if (e.getMessage().contains("List index") && e.getMessage().contains("out of bound")) { /* re-read list and recompute index */ } else throw e; }

Prevention

When it happens

Trigger: `UPDATE t SET l[5] = 'v'` when l has 2 elements; any negative index; index computed from stale client-side data after concurrent writes shrunk the list.

Common situations: Off-by-one errors (using size instead of size-1); stale UI index after list mutation; assuming CQL lists behave like zero-padded arrays.

Related errors


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

Appendix: source

Thrown at src/java/org/apache/cassandra/cql3/terms/Lists.java:374

            Guardrails.readBeforeWriteListOperationsEnabled
            .ensureEnabled("Setting of list items by index requiring read before write", builder.clientState);

            ByteBuffer index = idx.bindAndGet(builder);
            ByteBuffer value = t.bindAndGet(builder);

            if (index == null)
                throw new InvalidRequestException("Invalid null value for list index");
            if (index == ByteBufferUtil.UNSET_BYTE_BUFFER)
                throw new InvalidRequestException("Invalid unset value for list index");

            Row existingRow = builder.getPrefetchedRow(partitionKey, builder.currentClustering());
            int existingSize = existingSize(existingRow, column);
            int idx = ByteBufferUtil.toInt(index);
            if (existingSize == 0)
                throw new InvalidRequestException("Attempted to set an element on a list which is null");
            if (idx < 0 || idx >= existingSize)
                throw new InvalidRequestException(String.format("List index %d out of bound, list has size %d", idx, existingSize));

            CellPath elementPath = existingRow.getComplexColumnData(column).getCellByIndex(idx).path();
            if (value == null)
                builder.addTombstone(column, elementPath);
            else if (value != ByteBufferUtil.UNSET_BYTE_BUFFER)
                builder.addCell(column, elementPath, value);
        }
    }

    public static class Appender extends Operation
    {
        public Appender(ColumnMetadata column, Term t)
        {
            super(column, t);
        }

        public void execute(DecoratedKey partitionKey, RowUpdateBuilder builder) throws InvalidRequestException
        {

View on GitHub (pinned to 88fd0f6a0e)