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

  1. Fix the client/driver to encode string fields as UTF-8 before sending
  2. Inspect the hex bytes in the message to identify the corrupted field and check for framing desync
  3. Verify client and server agree on the native protocol version; downgrade via --protocol-version if a proxy mangles frames
  4. 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

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


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)