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

  1. Count the '?' markers in the CQL string and supply exactly that many values in order
  2. Re-prepare the statement if the query text changed since the values were built
  3. Use the driver's bound statement API (bind) instead of manual positional arrays so counts are checked
  4. 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

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


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