apache/cassandra · error · InvalidRequestException
there were %d markers(?) in CQL but %d bound variables
Error message
there were %d markers(?) in CQL but %d bound variables
What it means
Before executing a prepared statement, Cassandra validates that the number of supplied bound values (from QueryOptions) equals the number of bind markers in the statement. A mismatch means the driver supplied the wrong number of variables, so execution is refused with InvalidRequestException.
Source
Thrown at src/java/org/apache/cassandra/cql3/QueryProcessor.java:916
public ResultMessage processPrepared(CQLStatement statement,
QueryState state,
QueryOptions options,
Map<String, ByteBuffer> customPayload,
Dispatcher.RequestTime requestTime)
throws RequestExecutionException, RequestValidationException
{
return processPrepared(statement, state, options, requestTime);
}
public ResultMessage processPrepared(CQLStatement statement, QueryState queryState, QueryOptions options, Dispatcher.RequestTime requestTime)
throws RequestExecutionException, RequestValidationException
{
int variablesSize = options.getValuesSize();
// Check to see if there are any bound variables to verify
if (!(variablesSize == 0 && statement.getBindVariables().isEmpty()))
{
if (variablesSize != statement.getBindVariables().size())
throw new InvalidRequestException(String.format("there were %d markers(?) in CQL but %d bound variables",
statement.getBindVariables().size(),
variablesSize));
// at this point there is a match in count between markers and variables that is non-zero
if (logger.isTraceEnabled())
for (int i = 0; i < variablesSize; i++)
logger.trace("[{}] '{}'", i+1, options.getValues().get(i));
}
metrics.preparedStatementsExecuted.inc();
return processStatement(statement, queryState, options, requestTime);
}
public ResultMessage processBatch(BatchStatement statement,
QueryState state,
BatchQueryOptions options,
Map<String, ByteBuffer> customPayload,
Dispatcher.RequestTime requestTime)View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Count the '?' markers in the CQL string and supply exactly that many values in order
- Re-prepare the statement if the query text changed since the values were built
- Use the driver's bound statement API (bind) instead of manual positional arrays so counts are checked
- Log statement.getBindVariables().size() vs supplied values to locate the off-by-N
Example fix
// before
session.execute(prepared.bind(v1, v2)); // statement has 3 markers
// after
BoundStatement bs = prepared.bind();
bs.setString("c1", v1).setInt("c2", v2).setTimestamp("c3", v3); // all 3 bound Defensive patterns
Strategy: validation
Validate before calling
if (values.size() != statement.getPreparedId().boundVariables().size())
throw new IllegalStateException("expected " + statement.getPreparedId().boundVariables().size() + " values, got " + values.size()); Try / catch
try { session.execute(prepared.bind(values)); } catch (InvalidRequestException e) { if (e.getMessage().contains("markers(?) in CQL but")) rebuildValuesAndRetry(); else throw e; } Prevention
- Always bind values through the driver's BoundStatement API
- Re-prepare statements after any query-text change
- Keep value-list construction adjacent to the query string definition
When it happens
Trigger: Executing a prepared statement (QueryProcessor.processStatement / executeInternal with QueryOptions) where options.getValuesSize() differs from statement.getBindVariables().size(); e.g. passing positional values to a named-marker statement, or reusing values from a modified query.
Common situations: Application code that caches the statement but builds the value list independently; driver/statement mismatch after a schema or query edit; hand-rolled native-protocol clients sending wrong value counts; executeInternal callers constructing QueryOptions manually.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Value for a map addition has to be a map, but was: '%s'
- Invalid amount of bind variables
- Too many markers(?). %d markers exceed the allowed maximum o
- Prepared statement of size %d bytes is larger than allowed m
- 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/a989efb628f9232f.
Report an issue: GitHub.