apache/cassandra · error · org.apache.cassandra.transport.ProtocolException
Cannot decode string as UTF8: '" +…
Error message
Cannot decode string as UTF8: '" + ByteBufferUtil.bytesToHex(buffer) + "'; " + e
What it means
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.
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
Example fix
// before byte[] bad = value.getBytes(Charset.defaultCharset()); // after byte[] ok = value.getBytes(StandardCharsets.UTF_8);
Defensive patterns
Strategy: try-catch
Validate before calling
// client side: verify bytes are valid UTF-8 before sending
boolean validUtf8 = CharsetDecoder.newDecoder()
.onMalformedInput(CodingErrorAction.REPORT)
.decode(ByteBuffer.wrap(bytes)).hasRemaining() == false || true; // use strict decode
Try / catch
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; } Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Attempted to encode a response with an unset stream id:
- Beta version of server used
- Cannot convert value
- Cannot read value of length
- Cannot serialize RedundantStatus larger than 0xFFFF…
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/1f22516b3c52470e.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/transport/CBUtil.java:139
return dst.flip().toString();
}
private static String readString(ByteBuf cb, int length)
{
if (length == 0)
return "";
ByteBuffer buffer = cb.nioBuffer(cb.readerIndex(), length);
try
{
String str = decodeString(buffer);
cb.readerIndex(cb.readerIndex() + length);
return str;
}
catch (IllegalStateException | CharacterCodingException e)
{
throw new ProtocolException("Cannot decode string as UTF8: '" + ByteBufferUtil.bytesToHex(buffer) + "'; " + e);
}
}
public static String readString(ByteBuf cb)
{
try
{
int length = cb.readUnsignedShort();
return readString(cb, length);
}
catch (IndexOutOfBoundsException e)
{
throw new ProtocolException("Not enough bytes to read an UTF8 serialized string preceded by its 2 bytes length");
}
}
/**
* Write US-ASCII strings. It does not work if containing any char > 0x007F (127)View on GitHub (pinned to 88fd0f6a0e)