{"record":{"id":"d12cbb0931d4d92f","repo":"apache/cassandra","slug":"invalid-batch-message-type","errorCode":null,"errorMessage":"Invalid BATCH message type ","messagePattern":"Invalid BATCH message type ","errorType":"exception","errorClass":"ProtocolException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/transport/messages/BatchMessage.java","lineNumber":130,"sourceCode":"\n                size += CBUtil.sizeOfValueListOfByteArrays(msg.values.get(i));\n            }\n            size += version.isSmallerThan(ProtocolVersion.V3)\n                  ? CBUtil.sizeOfConsistencyLevel(msg.options.getConsistency())\n                  : QueryOptions.codec.encodedSize(msg.options, version);\n            return size;\n        }\n\n        private BatchStatement.Type toType(byte b)\n        {\n            if (b == 0)\n                return BatchStatement.Type.LOGGED;\n            else if (b == 1)\n                return BatchStatement.Type.UNLOGGED;\n            else if (b == 2)\n                return BatchStatement.Type.COUNTER;\n            else\n                throw new ProtocolException(\"Invalid BATCH message type \" + b);\n        }\n\n        private byte fromType(BatchStatement.Type type)\n        {\n            switch (type)\n            {\n                case LOGGED:   return 0;\n                case UNLOGGED: return 1;\n                case COUNTER:  return 2;\n                default:\n                    throw new AssertionError();\n            }\n        }\n    };\n\n    public final BatchStatement.Type batchType;\n    public final List<Object> queryOrIdList;\n    public final List<byte[][]> values;","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/transport/messages/BatchMessage.java#L112-L148","documentation":"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.","triggerScenarios":"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.","commonSituations":"Hand-written protocol clients writing the wrong batch-type byte; byte-shift corruption from wrong compression negotiation; proxy/transformation middleware re-encoding frames incorrectly.","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."],"exampleFix":"// before\nbody.writeByte(3); // invalid batch type\n// after\nbody.writeByte(0); // LOGGED (1=UNLOGGED, 2=COUNTER)","handlingStrategy":"validation","validationCode":"// when hand-encoding a BATCH header\nint typeFlag = batchType.ordinal(); // LOGGED=0, UNLOGGED=1, COUNTER=2\nif (typeFlag < 0 || typeFlag > 2) throw new IllegalArgumentException(\"batch type must be 0-2\");","typeGuard":null,"tryCatchPattern":"try { batch(); } catch (ProtocolException e) { if (e.getMessage().contains(\"Invalid BATCH message type\")) dumpAndInspectFrame(); }","preventionTips":["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"],"tags":["batch","protocol","deserialization","native-protocol"],"backgroundTag":"invalid-enum-value","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}