{"record":{"id":"1f22516b3c52470e","repo":"apache/cassandra","slug":"cannot-decode-string-as-utf8-bytebufferutil","errorCode":null,"errorMessage":"Cannot decode string as UTF8: '\" + ByteBufferUtil.bytesToHex(buffer) + \"'; \" + e","messagePattern":"Cannot decode string as UTF8: '\" \\+ ByteBufferUtil\\.bytesToHex\\(buffer\\) \\+ \"'; \" \\+ e","errorType":"exception","errorClass":"org.apache.cassandra.transport.ProtocolException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/transport/CBUtil.java","lineNumber":139,"sourceCode":"\n        return dst.flip().toString();\n    }\n\n    private static String readString(ByteBuf cb, int length)\n    {\n        if (length == 0)\n            return \"\";\n\n        ByteBuffer buffer = cb.nioBuffer(cb.readerIndex(), length);\n        try\n        {\n            String str = decodeString(buffer);\n            cb.readerIndex(cb.readerIndex() + length);\n            return str;\n        }\n        catch (IllegalStateException | CharacterCodingException e)\n        {\n            throw new ProtocolException(\"Cannot decode string as UTF8: '\" + ByteBufferUtil.bytesToHex(buffer) + \"'; \" + e);\n        }\n    }\n\n    public static String readString(ByteBuf cb)\n    {\n        try\n        {\n            int length = cb.readUnsignedShort();\n            return readString(cb, length);\n        }\n        catch (IndexOutOfBoundsException e)\n        {\n            throw new ProtocolException(\"Not enough bytes to read an UTF8 serialized string preceded by its 2 bytes length\");\n        }\n    }\n\n    /**\n     * Write US-ASCII strings. It does not work if containing any char > 0x007F (127)","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/transport/CBUtil.java#L121-L157","documentation":"CBUtil.readString(ByteBuf, int) decodes a length-prefixed CQL protocol frame field as UTF-8. If the bytes fail UTF-8 decoding (CharacterCodingException) or the buffer is in an illegal state, it wraps the failure in a ProtocolException including the hex of the offending bytes. It indicates the wire payload was not valid UTF-8 where the protocol requires it.","triggerScenarios":"A native-protocol frame carries a string field whose bytes are not valid UTF-8 (e.g., a driver or proxy sending binary/latin-1 data in keyspace names, query strings, or other string fields); reading a non-string payload as a string due to framing desync.","commonSituations":"Corrupt or truncated frames behind a proxy; custom clients writing strings with wrong charset; version mismatch causing a field to be parsed as a string when it is raw bytes.","solutions":["Fix the client/driver to encode string fields as UTF-8 before sending","Inspect the hex bytes in the message to identify the corrupted field and check for framing desync","Verify client and server agree on the native protocol version; downgrade via --protocol-version if a proxy mangles frames","Capture the frame with a packet sniffer to confirm the payload"],"exampleFix":"// before\nbyte[] bad = value.getBytes(Charset.defaultCharset());\n// after\nbyte[] ok = value.getBytes(StandardCharsets.UTF_8);","handlingStrategy":"try-catch","validationCode":"// client side: verify bytes are valid UTF-8 before sending\nboolean validUtf8 = CharsetDecoder.newDecoder()\n    .onMalformedInput(CodingErrorAction.REPORT)\n    .decode(ByteBuffer.wrap(bytes)).hasRemaining() == false || true; // use strict decode\n","typeGuard":null,"tryCatchPattern":"try { ... } catch (com.datastax.driver.core.exceptions.ProtocolError | io.netty handler ProtocolException e) { if (e.getMessage().contains(\"Cannot decode string as UTF8\")) { dumpFrameHex(); reconnect(); } else throw e; }","preventionTips":["Always encode protocol strings with StandardCharsets.UTF_8","Keep client, driver, and server on the same native protocol version","Log the hex bytes from the message to spot corrupted fields"],"tags":["cql-protocol","utf8","serialization"],"backgroundTag":"invalid-argument-format","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"}