apache/cassandra · error · IllegalArgumentException

Non-hex characters in <str>

Error message

Non-hex characters in <str>

What it means

Bytes.fromRawHexString converts a hex character pair stream into bytes using a lookup table where non-hex characters map to -1. If either nibble of any pair is -1, this IllegalArgumentException naming the whole offending string is thrown. It is the low-level validator behind fromHexString's content check.

Source

Thrown at src/java/org/apache/cassandra/cql3/functions/types/utils/Bytes.java:214

    /**
     * Converts a CQL hex string representation into a byte array.
     *
     * <p>A CQL blob string representation consist of the hexadecimal representation of the blob
     * bytes.
     *
     * @param str       the string converted in hex representation.
     * @param strOffset he offset for starting the string conversion
     * @return the byte array which the String was representing.
     */
    private static byte[] fromRawHexString(String str, int strOffset)
    {
        byte[] bytes = new byte[(str.length() - strOffset) / 2];
        for (int i = 0; i < bytes.length; i++)
        {
            byte halfByte1 = charToByte[str.charAt(strOffset + i * 2)];
            byte halfByte2 = charToByte[str.charAt(strOffset + i * 2 + 1)];
            if (halfByte1 == -1 || halfByte2 == -1)
                throw new IllegalArgumentException("Non-hex characters in " + str);
            bytes[i] = (byte) ((halfByte1 << 4) | halfByte2);
        }
        return bytes;
    }
}

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Strip all whitespace and the 0x prefix, then verify the string matches ^[0-9a-fA-F]+$ before conversion.
  2. Sanitize the input (remove spaces/underscores/separators commonly added for readability).
  3. Use fromHexString (which skips the 2-char prefix) instead of calling fromRawHexString with a prefixed string.
  4. Locate the bad character by scanning with Character.digit(c, 16) == -1 and report its index upstream.

Example fix

// before
byte[] b = Bytes.fromRawHexString("ab cd"); // space is non-hex
// after
byte[] b = Bytes.fromRawHexString("abcd"); // strip whitespace first
Defensive patterns

Strategy: validation

Validate before calling

String hex = raw.replaceAll("\\s", ""); if (!hex.matches("[0-9a-fA-F]+") || hex.length() % 2 != 0) throw new IllegalArgumentException("invalid hex: " + raw);

Try / catch

try { return Bytes.fromHexString(s); } catch (IllegalArgumentException e) { if (e.getMessage().startsWith("Non-hex characters")) throw new MalformedHexException(s, e); throw e; }

Prevention

When it happens

Trigger: fromHexString("0xzz12"), whitespace inside the hex like "0xab cd" (space is not hex), a '0x' prefix accidentally passed to fromRawHexString (which starts at index 0), Unicode look-alike characters pasted from docs.

Common situations: Copy-paste from formatted logs with spaces or line breaks inside hex; manual transcription errors; calling fromRawHexString directly with a prefixed string so 'x' becomes a non-hex character.

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/50044c99f23ec489. Report an issue: GitHub.