apache/cassandra · error · InvalidRequestException

Key may not be empty

Error message

Key may not be empty

What it means

QueryProcessor.validateKey() rejects partition keys that are null or zero-length, because Cassandra cannot store or route rows with an empty partition key under the storage format used (short-length-prefixed keys). The check runs before executing any statement that carries a key.

Source

Thrown at src/java/org/apache/cassandra/cql3/QueryProcessor.java:289

        preparedStatements.invalidate(id);
        SystemKeyspace.removePreparedStatement(id);
    }

    public HashMap<MD5Digest, Prepared> getPreparedStatements()
    {
        return new HashMap<>(preparedStatements.asMap());
    }

    public Prepared getPrepared(MD5Digest id)
    {
        return preparedStatements.getIfPresent(id);
    }

    public static void validateKey(ByteBuffer key) throws InvalidRequestException
    {
        if (key == null || key.remaining() == 0)
        {
            throw new InvalidRequestException("Key may not be empty");
        }
        if (key == ByteBufferUtil.UNSET_BYTE_BUFFER)
            throw new InvalidRequestException("Key may not be unset");

        // check that key can be handled by ByteArrayUtil.writeWithShortLength and ByteBufferUtil.writeWithShortLength
        if (key.remaining() > FBUtilities.MAX_UNSIGNED_SHORT)
        {
            throw new InvalidRequestException("Key length of " + key.remaining() +
                                              " is longer than maximum of " + FBUtilities.MAX_UNSIGNED_SHORT);
        }
    }

    public ResultMessage processStatement(CQLStatement statement, QueryState queryState, QueryOptions options, Dispatcher.RequestTime requestTime)
    throws RequestExecutionException, RequestValidationException
    {
        logger.trace("Process {} @CL.{}", statement, options.getConsistency());
        ClientState clientState = queryState.getClientState();
        statement.authorize(clientState);

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Validate the partition key is non-empty before binding/executing the query.
  2. Fix upstream data or serialization code that produced an empty key.
  3. If a sentinel key is needed, use a non-empty value instead of an empty buffer.

Example fix

// before
byte[] key = new byte[0];
stmt.bind(key);
// after
if (keyBytes == null || keyBytes.length == 0) throw new IllegalArgumentException("key required");
stmt.bind(keyBytes);
Defensive patterns

Strategy: validation

Validate before calling

if (key == null || key.remaining() == 0) throw new IllegalArgumentException("partition key must be non-empty");

Type guard

static boolean isValidKey(ByteBuffer k) { return k != null && k.remaining() > 0 && k != ByteBufferUtil.UNSET_BYTE_BUFFER && k.remaining() <= FBUtilities.MAX_UNSIGNED_SHORT; }

Try / catch

try { session.execute(stmt); } catch (InvalidRequestException e) { if (e.getMessage().equals("Key may not be empty")) { /* fix key serialization */ } }

Prevention

When it happens

Trigger: Calling validateKey / executing a statement whose partition key ByteBuffer is null or has remaining()==0, e.g. binding an empty byte[] or a empty string key.

Common situations: Application serializes an empty string/byte array as the partition key; deserialization produced a zero-length buffer; token-aware routing code extracting an empty key.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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