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

  1. Always include CQL_VERSION (e.g. "3.0.0") in the STARTUP options map
  2. Check any code that builds/sanitizes the options map so it doesn't drop the version entry
  3. Use a maintained driver that sends STARTUP correctly rather than hand-rolled frames
  4. 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

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


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)