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
- Compute the region from the array itself: bytes2base64(bs, off, bs.length - off, code).
- Use bytes2base64(bs) or bytes2base64(bs, off, bs.length - off) so the array drives the bounds.
- 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
- Compute remaining as bs.length - off, never bs.length.
- Let the array drive bounds via bytes2base64(byte[]).
- Beware int overflow on off + len for very large arrays — they are unrealistic here but validate the producer.
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
- bytes2base64: length < 0, length is {}
- base642bytes: offset < 0, offset is {}
- base642bytes: length < 0, length is {}
- base642bytes: offset + length > string length.
- unterminated escape sequence at index ${i} of: ${str}
AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14).
Data as JSON: /api/errors/5988a6a99d5bb5d4.
Report an issue: GitHub.