apache/cassandra · error · ProtocolException
Invalid BATCH message type
Error message
Invalid BATCH message type
What it means
ProtocolException from BatchMessage codec's toType helper when the BATCH type byte is not 0 (LOGGED), 1 (UNLOGGED), or 2 (COUNTER). decode validated query kinds but this byte denotes the batch kind itself; an out-of-range value means a malformed or newer-protocol frame the server cannot interpret.
Solutions
- Fix the producer to encode type as 0 (LOGGED), 1 (UNLOGGED), or 2 (COUNTER).
- Verify client/server compression settings match to rule out byte-shift corruption.
- Dump the raw frame bytes and compare against the native protocol v-spec BATCH layout.
- Use the java driver's BatchStatement API so the type byte is encoded correctly.
Example fix
// before body.writeByte(3); // invalid batch type // after body.writeByte(0); // LOGGED (1=UNLOGGED, 2=COUNTER)
Defensive patterns
Strategy: validation
Validate before calling
// when hand-encoding a BATCH header
int typeFlag = batchType.ordinal(); // LOGGED=0, UNLOGGED=1, COUNTER=2
if (typeFlag < 0 || typeFlag > 2) throw new IllegalArgumentException("batch type must be 0-2"); Try / catch
try { batch(); } catch (ProtocolException e) { if (e.getMessage().contains("Invalid BATCH message type")) dumpAndInspectFrame(); } Prevention
- Encode LOGGED/UNLOGGED/COUNTER as 0/1/2 exactly
- Use BatchStatement.fromType/fromType-style helpers rather than raw bytes
- Use the java driver to guarantee spec-compliant encoding
When it happens
Trigger: A BATCH frame whose header type byte is not 0/1/2 — sent by a buggy custom client, corrupted in transit due to compression/framing mismatch, or mangled by an intermediary.
Common situations: Hand-written protocol clients writing the wrong batch-type byte; byte-shift corruption from wrong compression negotiation; proxy/transformation middleware re-encoding frames incorrectly.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Invalid query kind in BATCH messages. Must be 0 or 1 but…
- Invalid IP address ( . . . ) while deserializing inet…
- Invalid IP address while deserializing inet address
- Invalid value for the paging state
- Out of bound timestamp, must be in
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/d12cbb0931d4d92f.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/transport/messages/BatchMessage.java:130
size += CBUtil.sizeOfValueListOfByteArrays(msg.values.get(i));
}
size += version.isSmallerThan(ProtocolVersion.V3)
? CBUtil.sizeOfConsistencyLevel(msg.options.getConsistency())
: QueryOptions.codec.encodedSize(msg.options, version);
return size;
}
private BatchStatement.Type toType(byte b)
{
if (b == 0)
return BatchStatement.Type.LOGGED;
else if (b == 1)
return BatchStatement.Type.UNLOGGED;
else if (b == 2)
return BatchStatement.Type.COUNTER;
else
throw new ProtocolException("Invalid BATCH message type " + b);
}
private byte fromType(BatchStatement.Type type)
{
switch (type)
{
case LOGGED: return 0;
case UNLOGGED: return 1;
case COUNTER: return 2;
default:
throw new AssertionError();
}
}
};
public final BatchStatement.Type batchType;
public final List<Object> queryOrIdList;
public final List<byte[][]> values;View on GitHub (pinned to 88fd0f6a0e)