apache/cassandra · error · InvalidRequestException
Too many markers(?). %d markers exceed the allowed maximum o
Error message
Too many markers(?). %d markers exceed the allowed maximum of %d
What it means
Cassandra limits the number of bind markers (?) in a single prepared statement to 65535 (MAX_UNSIGNED_SHORT), because bound variable indexes are encoded as unsigned shorts in the native protocol. When prepare() counts more bound terms than this limit it refuses to prepare the statement with InvalidRequestException.
Source
Thrown at src/java/org/apache/cassandra/cql3/QueryProcessor.java:815
if (clientState.getRawKeyspace() != null && !cachedWithKeyspace.fullyQualified) // For non-fully qualified statements, we always include keyspace to avoid ambiguity
return createResultMessage(hashWithKeyspace, cachedWithKeyspace);
}
else // legacy caches, pre-CASSANDRA-15252 behaviour
{
return createResultMessage(hashWithKeyspace, cachedWithKeyspace);
}
}
Prepared prepared = parseAndPrepare(queryString, clientState, false);
CQLStatement statement = prepared.statement;
if (!statement.eligibleAsPreparedStatement())
clientState.warnAboutUneligiblePreparedStatement(hashWithKeyspace);
int boundTerms = statement.getBindVariables().size();
if (boundTerms > FBUtilities.MAX_UNSIGNED_SHORT)
throw new InvalidRequestException(String.format("Too many markers(?). %d markers exceed the allowed maximum of %d", boundTerms, FBUtilities.MAX_UNSIGNED_SHORT));
if (prepared.fullyQualified)
{
ResultMessage.Prepared qualifiedWithoutKeyspace = storePreparedStatement(queryString, null, prepared);
ResultMessage.Prepared qualifiedWithKeyspace = null;
if (clientState.getRawKeyspace() != null)
qualifiedWithKeyspace = storePreparedStatement(queryString, clientState.getRawKeyspace(), prepared);
if (!useNewPreparedStatementBehaviour && qualifiedWithKeyspace != null)
return qualifiedWithKeyspace;
return qualifiedWithoutKeyspace;
}
else
{
if (prepared.statement.eligibleAsPreparedStatement())
clientState.warnAboutUseWithPreparedStatements(hashWithKeyspace, clientState.getRawKeyspace());
View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Reduce the number of bind markers by splitting the statement into multiple smaller statements or batches
- Use literal values instead of bind markers for some columns
- If inserting many rows, execute multiple INSERT statements instead of one giant statement
- Verify column count; wide denormalized tables may need remodeling (e.g. clustering rows instead of many columns)
Example fix
// before
String stmt = "INSERT INTO t (k,c1,c2,...) VALUES (?,?,?,...)"; // 70000 markers
// after
for (List<Object> row : rows) session.execute("INSERT INTO t (...) VALUES (?,...)", row); // one statement per row Defensive patterns
Strategy: validation
Validate before calling
int markers = countBindMarkers(cql); // count '?' outside string/quoted literals
if (markers > 65535) throw new IllegalArgumentException("Statement has " + markers + " markers; split it"); Try / catch
try { session.prepare(cql); } catch (InvalidRequestException e) { if (e.getMessage().contains("Too many markers")) splitAndRetry(cql); else throw e; } Prevention
- Count bind markers before preparing programmatically generated CQL
- Prefer many small statements over single mega-statements
- Model wide data as rows, not as hundreds of columns
- Remember the protocol limit is 65535 markers per statement
When it happens
Trigger: Calling prepare() (via session.prepare or QueryProcessor.prepare) on a CQL statement containing more than 65535 '?' bind markers, typically a very large INSERT/UPDATE or batch built programmatically.
Common situations: Code generators or ORMs that create one marker per column across thousands of columns; batch statements assembled in a loop without checking marker count; migration scripts converting rows into parameterized inserts.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- Value for a map addition has to be a map, but was: '%s'
- Invalid amount of bind variables
- Prepared statement of size %d bytes is larger than allowed m
- there were %d markers(?) in CQL but %d bound variables
- Prepared query with ID %s not found (either the query was no
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/8ea6b477d57906d5.
Report an issue: GitHub.