apache/dubbo · error · IndexOutOfBoundsException

bytes2base64: offset + length > array length.

Error message

bytes2base64: offset + length > array length.

What it means

Thrown by Bytes.bytes2base64(byte[], int off, int len, char[] code) when off + len exceeds bs.length, i.e. the requested encode region runs past the end of the byte array. It is a region-bounds precondition; the loop indexes bs[r++] up to off+len-1, so an out-of-range region would otherwise throw a raw ArrayIndexOutOfBoundsException deeper in the encode loop.

Source

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

    /**
     * to base64 string.
     *
     * @param bs   byte array.
     * @param off  offset.
     * @param len  length.
     * @param code base64 code(0-63 is base64 char,64 is pad char).
     * @return base64 string.
     */
    public static String bytes2base64(final byte[] bs, final int off, final int len, final char[] code) {
        if (off < 0) {
            throw new IndexOutOfBoundsException("bytes2base64: offset < 0, offset is " + off);
        }
        if (len < 0) {
            throw new IndexOutOfBoundsException("bytes2base64: length < 0, length is " + len);
        }
        if (off + len > bs.length) {
            throw new IndexOutOfBoundsException("bytes2base64: offset + length > array length.");
        }

        if (code.length < 64) {
            throw new IllegalArgumentException("Base64 code length < 64.");
        }

        boolean pad = code.length > 64; // has pad char.
        int num = len / 3, rem = len % 3, r = off, w = 0;
        char[] cs = new char[num * 4 + (rem == 0 ? 0 : pad ? 4 : rem + 1)];

        for (int i = 0; i < num; i++) {
            int b1 = bs[r++] & MASK8, b2 = bs[r++] & MASK8, b3 = bs[r++] & MASK8;

            cs[w++] = code[b1 >> 2];
            cs[w++] = code[(b1 << 4) & MASK6 | (b2 >> 4)];
            cs[w++] = code[(b2 << 2) & MASK6 | (b3 >> 6)];
            cs[w++] = code[b3 & MASK6];
        }

View on GitHub (pinned to 3a3043227f)

Solutions

  1. Compute the region from the array itself: bytes2base64(bs, off, bs.length - off, code).
  2. Use bytes2base64(bs) or bytes2base64(bs, off, bs.length - off) so the array drives the bounds.
  3. Validate at the producer: assert off + len <= bs.length before forwarding.

Example fix

// before
String s = Bytes.bytes2base64(bs, off, bs.length, Bytes.BASE64); // double-counts off
// after
String s = Bytes.bytes2base64(bs, off, bs.length - off, Bytes.BASE64);
Defensive patterns

Strategy: validation

Validate before calling

if (off < 0 || len < 0 || off + len > bs.length) {
    throw new IllegalArgumentException("bad region off=" + off + " len=" + len + " arr=" + bs.length);
}
String s = Bytes.bytes2base64(bs, off, len, Bytes.BASE64);

Type guard

static boolean validRegion(byte[] a, int off, int len) {
    return off >= 0 && len >= 0 && off + len <= a.length;
}

Try / catch

try {
    String s = Bytes.bytes2base64(bs, off, len, Bytes.BASE64);
} catch (IndexOutOfBoundsException e) {
    throw new IllegalArgumentException("encode region out of bounds", e);
}

Prevention

When it happens

Trigger: Passing an offset/length pair whose sum exceeds the array length, e.g. bytes2base64(bs, 2, bs.length, code) (forgets to subtract the offset); or a length copied from a different, larger array.

Common situations: Reusing a length from a larger source buffer after sub-slicing; miscomputing remaining = total when an offset is also given (must be bs.length - off); truncation/corruption of a length field on the wire.

Related errors


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