apache/cassandra · error · InvalidRequestException
Invalid tuple literal for %s: too many elements. Type %s exp
Error message
Invalid tuple literal for %s: too many elements. Type %s expects %d but got %d
What it means
Cassandra throws this when a tuple literal in a CQL statement contains more values than the target column's tuple type defines components for. Tuples in Cassandra have a fixed arity: a column declared, say, `frozen<tuple<int, text>>` accepts exactly 2 elements and no more. During statement validation (validateTupleAssignableTo, invoked via testTupleAssignment), the element list is compared element-by-element against the receiver's TupleType, and any excess element triggers this InvalidRequestException before execution.
Source
Thrown at src/java/org/apache/cassandra/cql3/terms/Tuples.java:189
/**
* Checks if the tuple with the specified elements can be assigned to the specified column.
*
* @param receiver the receiving column
* @param elements the tuple elements
* @throws InvalidRequestException if the tuple cannot be assigned to the specified column.
*/
public static void validateTupleAssignableTo(ColumnSpecification receiver,
List<? extends AssignmentTestable> elements)
{
if (!checkIfTupleType(receiver.type))
throw invalidRequest("Invalid tuple type literal for %s of type %s", receiver.name, receiver.type.asCQL3Type());
TupleType tt = getTupleType(receiver.type);
for (int i = 0; i < elements.size(); i++)
{
if (i >= tt.size())
{
throw invalidRequest("Invalid tuple literal for %s: too many elements. Type %s expects %d but got %d",
receiver.name, tt.asCQL3Type(), tt.size(), elements.size());
}
AssignmentTestable value = elements.get(i);
ColumnSpecification spec = componentSpecOf(receiver, i);
if (!value.testAssignment(receiver.ksName, spec).isAssignable())
throw invalidRequest("Invalid tuple literal for %s: component %d is not of type %s",
receiver.name, i, spec.type.asCQL3Type());
}
}
/**
* Tests that the tuple with the specified elements can be assigned to the specified column.
*
* @param receiver the receiving column
* @param elements the tuple elements
*/
public static AssignmentTestable.TestResult testTupleAssignment(ColumnSpecification receiver,View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Count the elements in the tuple literal and compare with the column definition (`DESCRIBE TABLE` or system_schema.columns shows the tuple type); remove extra elements so it matches the declared arity.
- If the extra element should be stored, ALTER the column to a wider tuple type (note: Cassandra only supports adding components at the end, e.g. ALTER TABLE ... ALTER c TYPE tuple<int, text, boolean> in older versions or recreate the column), then update the statement.
- If element count is dynamic in application code, validate `values.size() <= declaredTupleSize` before building the CQL literal, or use a separate collection column (list/set/map) instead of a tuple.
- After any tuple type change, restart/refresh prepared statement caches so stale literals against the old type are revalidated.
Example fix
// before: column is frozen<tuple<int, text>> (2 components) INSERT INTO t (k, c) VALUES (1, (1, 'a', true)); // after: literal arity matches the declared tuple type INSERT INTO t (k, c) VALUES (1, (1, 'a'));
Defensive patterns
Strategy: validation
Validate before calling
TupleType tt = (TupleType) column.getType();
if (values.size() > tt.size())
throw new IllegalArgumentException(
String.format("tuple for column %s expects at most %d elements, got %d",
column.getName(), tt.size(), values.size())); Prevention
- Generate INSERT/UPDATE statements from the live table metadata (driver SchemaMetadata) rather than hardcoding tuple arity.
- Use the driver's typed TupleValue API so arity and per-component types are enforced at bind time.
- Re-prepare statements after any ALTER that changes a tuple column type.
- Prefer dedicated collection columns (list/map) over tuples when element count can vary.
When it happens
Trigger: Executing INSERT/UPDATE/DELETE with a tuple literal like `c = (1, 'a', true)` against a column of type `tuple<int, text>`; calling `Tuples.validateTupleAssignableTo(receiver, elements)` (or `testTupleAssignment`) with `elements.size() > tupleType.size()`; binding a user-supplied list into a tuple column without checking arity; preparing statements where a schema change shortened the tuple type while cached literals still supply the old element count.
Common situations: Application code building tuple values dynamically from a list of unknown length; a schema migration that reduced the number of tuple components while old application versions still send the larger literal; typos in hand-written CQL where an extra value is pasted into the tuple; ORM/driver mapping layers that serialize the whole row object into a tuple field.
Related errors
- Tuple value contains too many fields (expected %s, got %s)
- message (caller-provided message string)
- messageTemplate (caller-provided message template, 1 arg)
- messageTemplate (caller-provided message template, 2 args)
- messageTemplate (caller-provided message template, 3 args)
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/1781bed3ea34a45e.
Report an issue: GitHub.