apache/cassandra · error · ProtocolException
Missing value CQL_VERSION in STARTUP message
Error message
Missing value CQL_VERSION in STARTUP message
What it means
The STARTUP message must include a CQL_VERSION option declaring which CQL specification the client speaks. If the option is absent, StartupMessage throws a ProtocolException, because the server cannot interpret the session without knowing the CQL version.
Solutions
- Always include CQL_VERSION (e.g. "3.0.0") in the STARTUP options map
- Check any code that builds/sanitizes the options map so it doesn't drop the version entry
- Use a maintained driver that sends STARTUP correctly rather than hand-rolled frames
- Verify with a protocol trace (netty logging / wireshark) that the option is actually on the wire
Example fix
// before
Map<String,String> opts = Map.of("COMPRESSION","lz4");
// after
Map<String,String> opts = Map.of("CQL_VERSION","3.0.0","COMPRESSION","lz4"); Defensive patterns
Strategy: validation
Validate before calling
if (!options.containsKey("CQL_VERSION"))
throw new IllegalArgumentException("STARTUP requires CQL_VERSION"); Type guard
boolean startupOptionsValid(Map<String,String> o) {
return o != null && o.containsKey("CQL_VERSION");
} Try / catch
try {
connection.startup(options);
} catch (ProtocolException e) {
if (e.getMessage().contains("Missing value CQL_VERSION")) {
options.put("CQL_VERSION", "3.0.0");
connection.startup(options);
} else throw e;
} Prevention
- Always send CQL_VERSION in STARTUP options
- Sanitize option maps carefully so required keys aren't stripped
- Use maintained drivers rather than hand-built frames
- Assert startup options in protocol-level integration tests
When it happens
Trigger: Sending a StartupMessage whose options map lacks the "CQL_VERSION" key — e.g. hand-built protocol frames, minimal proxies/drivers omitting startup options, or a config layer that strips empty option values.
Common situations: Custom/native-protocol clients built from incomplete examples; thin clients forwarding only COMPRESSION; test harnesses constructing bare STARTUP frames; drivers with broken option serialization.
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
- CQL version is not supported by the binary protocol…
- The page size cannot be 0
- The page size cannot be 0
- There were markers(?) in CQL but bound variables
- Unknown kind id in RESULT message
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/8d49d94e7bc44487.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/transport/messages/StartupMessage.java:88
}
};
private static final byte[] EMPTY_CLIENT_RESPONSE = new byte[0];
public final Map<String, String> options;
public StartupMessage(Map<String, String> options)
{
super(Message.Type.STARTUP);
this.options = options;
}
@Override
protected Message.Response execute(QueryState state, Dispatcher.RequestTime requestTime, boolean traceRequest)
{
String cqlVersion = options.get(CQL_VERSION);
if (cqlVersion == null)
throw new ProtocolException("Missing value CQL_VERSION in STARTUP message");
try
{
if (new CassandraVersion(cqlVersion).compareTo(new CassandraVersion("2.99.0")) < 0)
throw new ProtocolException(String.format("CQL version %s is not supported by the binary protocol (supported version are >= 3.0.0)", cqlVersion));
}
catch (IllegalArgumentException e)
{
throw new ProtocolException(e.getMessage());
}
if (options.containsKey(COMPRESSION))
{
String compression = toLowerCaseLocalized(options.get(COMPRESSION));
if (compression.equals("snappy"))
{
if (Compressor.SnappyCompressor.instance == null)
throw new ProtocolException("This instance does not support Snappy compression");View on GitHub (pinned to 88fd0f6a0e)