apache/cassandra · error · IllegalArgumentException

Invalid query, must be a %s statement but was: %s

Error message

Invalid query, must be a %s statement but was: %s

What it means

StressCQLSSTableWriter.parseStatement parses a CQL string with the ANTLR parser and then verifies that the resulting statement object is of the expected class (e.g. an INSERT for a writer opened as an insert writer, or DELETE/UPDATE for the corresponding variant). If the parsed statement is a different kind of statement, it throws IllegalArgumentException telling the caller what kind of statement was expected and what class was actually parsed. This guards the SSTable-writer API, which can only generate SSTables for the statement type it was constructed for.

Source

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

            if (insert.hasConditions())
                throw new IllegalArgumentException("Conditional statements are not supported");
            if (insert.isCounter())
                throw new IllegalArgumentException("Counter update statements are not supported");
            if (insert.getBindVariables().isEmpty())
                throw new IllegalArgumentException("Provided insert statement has no bind variables");

            return insert;
        }
    }

    public static <T extends CQLStatement.Raw> T parseStatement(String query, Class<T> klass, String type)
    {
        try
        {
            CQLStatement.Raw stmt = CQLFragmentParser.parseAnyUnhandled(CqlParser::query, query);

            if (!stmt.getClass().equals(klass))
                throw new IllegalArgumentException("Invalid query, must be a " + type + " statement but was: " + stmt.getClass());

            return klass.cast(stmt);
        }
        catch (RecognitionException | RequestValidationException e)
        {
            throw new IllegalArgumentException(e.getMessage(), e);
        }
    }
}

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Make the CQL string passed to the writer match the writer kind: use an INSERT statement for an insert writer.
  2. Check that the statement does not start with a different keyword (SELECT/UPDATE/DELETE/BEGIN) and remove trailing semicolons or comments that could confuse classification.
  3. If you need a different statement type, build the writer with the matching factory (StressCQLSSTableWriter.builder for inserts vs the delete/update variants).
  4. Wrap the call in try/catch (IllegalArgumentException) and print the actual parsed statement class from the message to diagnose the mismatch.

Example fix

// before
StressCQLSSTableWriter writer = StressCQLSSTableWriter.builder(schema, "UPDATE ks.t SET v = ? WHERE k = ?").build();
// after
StressCQLSSTableWriter writer = StressCQLSSTableWriter.builder(schema, "INSERT INTO ks.t (k, v) VALUES (?, ?)").build();
Defensive patterns

Strategy: validation

Validate before calling

String cql = "INSERT INTO ks.t (k, v) VALUES (?, ?)";
String firstWord = cql.trim().split("\\s+", 2)[0].toUpperCase();
if (!firstWord.equals("INSERT"))
    throw new IllegalArgumentException("Writer expects INSERT, got: " + firstWord);

Type guard

boolean isInsert(Class<? extends CQLStatement.Raw> actual, Class<? extends CQLStatement.Raw> expected) {
    return expected.equals(actual);
}

Try / catch

try {
    writer = StressCQLSSTableWriter.builder(schema, cql).build();
} catch (IllegalArgumentException e) {
    throw new IllegalStateException("CQL does not match writer kind: " + e.getMessage(), e);
}

Prevention

When it happens

Trigger: Calling StressCQLSSTableWriter.builder(...).build() for one operation kind (e.g. INSERT) and then passing a CQL string of a different kind (SELECT, UPDATE, DELETE) to the writer, so CQLFragmentParser.parseAnyUnhandled(CqlParser::query, query) returns a Raw statement whose class does not equal the expected klass.

Common situations: Copy-pasting a CQL statement of the wrong type into the writer builder; changing a schema string from INSERT to UPDATE (or adding options like IF NOT EXISTS) after configuring the writer; confusing compileOptions/insert vs update/delete writer factory methods in the stress tooling.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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