apache/cassandra · error · MarshalException

cannot parse '%s' as hex bytes

Error message

cannot parse '%s' as hex bytes

What it means

BytesType.fromString throws this when the source string cannot be converted from hex to bytes by Hex.hexToBytes. Blob values in CQL are hex strings; any non-hex character, odd-length string, or empty string causes NumberFormatException wrapped in this MarshalException.

Source

Thrown at src/java/org/apache/cassandra/db/marshal/BytesType.java:55

    private static final ByteBuffer MASKED_VALUE = ByteBufferUtil.EMPTY_BYTE_BUFFER;

    BytesType() {super(ComparisonType.BYTE_ORDER);} // singleton

    @Override
    public boolean allowsEmpty()
    {
        return true;
    }

    public ByteBuffer fromString(String source)
    {
        try
        {
            return ByteBuffer.wrap(Hex.hexToBytes(source));
        }
        catch (NumberFormatException e)
        {
            throw new MarshalException(String.format("cannot parse '%s' as hex bytes", source), e);
        }
    }

    @Override
    public Term fromJSONObject(Object parsed) throws MarshalException
    {
        try
        {
            String parsedString = (String) parsed;
            if (!parsedString.startsWith("0x"))
                throw new MarshalException(String.format("String representation of blob is missing 0x prefix: %s", parsedString));

            return new Constants.Value(BytesType.instance.fromString(parsedString.substring(2)));
        }
        catch (ClassCastException | MarshalException exc)
        {
            throw new MarshalException(String.format("Value '%s' is not a valid blob representation: %s", parsed, exc.getMessage()));
        }

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Provide valid even-length hex characters (0-9, a-f), e.g. 0x68656c6c6f
  2. Hex-encode the data properly: bytesToHex(byte[]) before insert
  3. If data is base64, decode it first then re-encode as hex
  4. Handle the 0x prefix exactly once — do not pass '0x' inside fromString if upstream already stripped it

Example fix

// before
INSERT INTO t (k, b) VALUES (1, 0xzz12);
// after
INSERT INTO t (k, b) VALUES (1, 0xdeadbeef);
Defensive patterns

Strategy: validation

Validate before calling

public static void assertHex(String s) {
    String h = s.startsWith("0x") ? s.substring(2) : s;
    if (h.isEmpty() || h.length() % 2 != 0 || !h.matches("[0-9a-fA-F]+"))
        throw new IllegalArgumentException("Invalid hex: " + s);
}

Prevention

When it happens

Trigger: INSERT of blob literal 0xzz12 or odd-length hex like 'abc'; passing raw binary/text that was never hex-encoded; fromString called directly with a still-0x-prefixed string containing non-hex chars (e.g. the 'x').

Common situations: Hand-assembling blob literals in cqlsh; hex encoders producing prefixed strings passed unstripped to fromString; base64 data pasted where hex is required; log-replay of CQL statements with mangled blobs.

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/09f8e8f8024a35ee. Report an issue: GitHub.