apache/dubbo · error · IndexOutOfBoundsException

hex2bytes: offset + length > array length.

Error message

hex2bytes: offset + length > array length.

What it means

Thrown by Bytes.hex2bytes(String, int, int) when off + len exceeds the source string length. This upper-bound check ensures the requested character region [off, off+len) lies within the string, preventing StringIndexOutOfBoundsException during charAt reads in the conversion loop. It is the last of the four hex2bytes validations.

Solutions

  1. Recompute len against the actual string length: len = Math.min(len, str.length() - off).
  2. Use hex2bytes(String) for the whole string.
  3. Ensure the string and its computed region are derived from the same source.

Example fix

// before
String hex = fullHex.substring(0, 10);
byte[] b = Bytes.hex2bytes(hex, 0, fullHex.length()); // throws [157]

// after
byte[] b = Bytes.hex2bytes(hex, 0, hex.length());
Defensive patterns

Strategy: validation

Validate before calling

if (off + len > str.length()) len = str.length() - off; // clamp
byte[] b = Bytes.hex2bytes(str, off, len);

Prevention

When it happens

Trigger: Calling Bytes.hex2bytes(str, off, len) where off + len > str.length(). Usually a stale length computed against a longer string, or a substring that was trimmed but the old length retained.

Common situations: Truncating a hex string but keeping the original length; off-by-one including the null terminator or delimiter in len; concatenation/removal that changed string size after length was computed.

Related errors


AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14). Data as JSON: /api/errors/3315257157e9355c. Report an issue: GitHub.

Appendix: source

Thrown at dubbo-common/src/main/java/org/apache/dubbo/common/io/Bytes.java:449

     *
     * @param str hex string.
     * @param off offset.
     * @param len length.
     * @return byte array.
     */
    public static byte[] hex2bytes(final String str, final int off, int len) {
        if ((len & 1) == 1) {
            throw new IllegalArgumentException("hex2bytes: ( len & 1 ) == 1.");
        }

        if (off < 0) {
            throw new IndexOutOfBoundsException("hex2bytes: offset < 0, offset is " + off);
        }
        if (len < 0) {
            throw new IndexOutOfBoundsException("hex2bytes: length < 0, length is " + len);
        }
        if (off + len > str.length()) {
            throw new IndexOutOfBoundsException("hex2bytes: offset + length > array length.");
        }

        int num = len / 2, r = off, w = 0;
        byte[] b = new byte[num];
        for (int i = 0; i < num; i++) {
            b[w++] = (byte) (hex(str.charAt(r++)) << 4 | hex(str.charAt(r++)));
        }
        return b;
    }

    /**
     * to base64 string.
     *
     * @param b byte array.
     * @return base64 string.
     */
    public static String bytes2base64(byte[] b) {
        return bytes2base64(b, 0, b.length, BASE64);

View on GitHub (pinned to 3a3043227f)