apache/cassandra · error · InvalidRequestException

Invalid number of arguments, expecting

Error message

Invalid number of arguments, expecting %d values but got %d

What it means

StressCQLSSTableWriter.rawAddRow(List<ByteBuffer>) binds the provided values to the bound variables of the prepared INSERT statement. It throws InvalidRequestException when the number of supplied values does not exactly match the number of bind variables in the INSERT statement. The expected and actual counts are included in the message.

Solutions

  1. Count the '?' placeholders in your INSERT statement and match the list size exactly.
  2. Rebuild the values list from the table schema to ensure column order/count alignment.
  3. Add an assertion before the call comparing values.size() against the known bind count.
  4. Use the Map/Object[]-based addRow variants that bind by name instead of position.

Example fix

// before
writer.rawAddRow(Arrays.asList(key, col1)); // INSERT has 3 bind variables
// after
writer.rawAddRow(Arrays.asList(key, col1, col2));
Defensive patterns

Strategy: validation

Validate before calling

// values built per row
List<ByteBuffer> values = buildRow();
if (values.size() != expectedBindCount) throw new IllegalArgumentException("expected " + expectedBindCount + " got " + values.size());
writer.rawAddRow(values);

Try / catch

try { writer.rawAddRow(values); }
catch (InvalidRequestException e) {
    // message contains expected vs actual counts; log the row for inspection
    throw new IllegalArgumentException("row shape mismatch: " + e.getMessage(), e);
}

Prevention

When it happens

Trigger: Calling rawAddRow(values) where values.size() != boundNames.size(), i.e. providing fewer or more ByteBuffers than the '?' placeholders in the using() INSERT statement.

Common situations: Schema changed (column added/removed) but the value-building code was not updated; accidentally passing a row with nulls omitted; off-by-one when concatenating key and column values.

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/f239eb02f9970fa5. Report an issue: GitHub.

Appendix: source

Thrown at tools/stress/src/org/apache/cassandra/io/sstable/StressCQLSSTableWriter.java:259

    throws InvalidRequestException, IOException
    {
        return rawAddRow(Arrays.asList(values));
    }

    /**
     * Adds a new row to the writer given already serialized values.
     * <p>
     * This is a shortcut for {@code rawAddRow(Arrays.asList(values))}.
     *
     * @param values the row values (corresponding to the bind variables of the
     * insertion statement used when creating by this writer) as binary.
     * @return this writer.
     */
    public StressCQLSSTableWriter rawAddRow(List<ByteBuffer> values)
    throws InvalidRequestException, IOException
    {
        if (values.size() != boundNames.size())
            throw new InvalidRequestException(String.format("Invalid number of arguments, expecting %d values but got %d", boundNames.size(), values.size()));

        QueryOptions options = QueryOptions.forInternalCalls(null, values);
        ClientState state = ClientState.forInternalCalls();
        List<ByteBuffer> keys = insert.buildPartitionKeyNames(options, state);
        SortedSet<Clustering<?>> clusterings = insert.createClustering(options, state);

        long now = currentTimeMillis();
        // Note that we asks indexes to not validate values (the last 'false' arg below) because that triggers a 'Keyspace.open'
        // and that forces a lot of initialization that we don't want.
        RowUpdateBuilder builder = new RegularRowUpdateBuilder(insert.metadata(),
                                                               ClientState.forInternalCalls(),
                                                               options,
                                                               insert.getTimestamp(TimeUnit.MILLISECONDS.toMicros(now), options),
                                                               (int) TimeUnit.MILLISECONDS.toSeconds(now),
                                                               insert.getTimeToLive(options),
                                                               null);

        try

View on GitHub (pinned to 88fd0f6a0e)