apache/dubbo · error · ArrayIndexOutOfBoundsException
buffer srcBytes.length=%d, srcIdx=%d, srcSize=%d, destChars.
Error message
buffer srcBytes.length=%d, srcIdx=%d, srcSize=%d, destChars.length=%d, destIdx=%d
What it means
Thrown by Utf8Utils.decodeUtf8 as an ArrayIndexOutOfBoundsException when the source/destination buffer bounds are violated: srcIdx or srcSize is negative, srcIdx+srcSize exceeds srcBytes.length, or destIdx+srcSize exceeds destChars.length. This is a pre-flight bounds guard before any byte is decoded, so it signals a caller arithmetic error, not bad data.
Source
Thrown at dubbo-common/src/main/java/org/apache/dubbo/common/utils/Utf8Utils.java:53
/**
* See original <a href=
* "https://github.com/protocolbuffers/protobuf/blob/master/java/core/src/main/java/com/google/protobuf/Utf8.java"
* >Utf8.java</a>
*/
public final class Utf8Utils {
private Utf8Utils() {
//empty
}
public static int decodeUtf8(byte[] srcBytes, int srcIdx, int srcSize, char[] destChars, int destIdx) {
// Bitwise OR combines the sign bits so any negative value fails the check.
if ((srcIdx | srcSize | srcBytes.length - srcIdx - srcSize) < 0
|| (destIdx | destChars.length - destIdx - srcSize) < 0) {
String exMsg = String.format("buffer srcBytes.length=%d, srcIdx=%d, srcSize=%d, destChars.length=%d, " +
"destIdx=%d", srcBytes.length, srcIdx, srcSize, destChars.length, destIdx);
throw new ArrayIndexOutOfBoundsException(
exMsg);
}
int offset = srcIdx;
final int limit = offset + srcSize;
final int destIdx0 = destIdx;
// Optimize for 100% ASCII (Hotspot loves small simple top-level loops like this).
// This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII).
while (offset < limit) {
byte b = srcBytes[offset];
if (!DecodeUtil.isOneByte(b)) {
break;
}
offset++;
DecodeUtil.handleOneByteSafe(b, destChars, destIdx++);
}
View on GitHub (pinned to 3a3043227f)
Solutions
- Verify srcIdx>=0, srcSize>=0, and srcIdx+srcSize<=srcBytes.length before calling decodeUtf8.
- Ensure destChars is allocated with at least srcSize chars (worst case 1 char per byte for the safe variant) and destIdx+srcSize<=destChars.length.
- If the inputs come from a length-prefixed stream, validate the length against the remaining buffer before decoding.
- Check for serialization protocol version mismatch between producer and consumer if the length prefix looks wrong.
Example fix
// before
char[] out = new char[asciiLen]; // too small if non-ascii
Utf8Utils.decodeUtf8(bytes, 0, bytes.length, out, 0);
// after
char[] out = new char[bytes.length]; // safe upper bound
if (0 > 0 || bytes.length > bytes.length || bytes.length > out.length) {
throw new IllegalArgumentException("bad bounds");
}
Utf8Utils.decodeUtf8(bytes, 0, bytes.length, out, 0); Defensive patterns
Strategy: validation
Validate before calling
void checkBounds(byte[] src, int srcIdx, int srcSize, char[] dest, int destIdx) {
if (srcIdx < 0 || srcSize < 0 || srcIdx + srcSize > src.length
|| destIdx < 0 || destIdx + srcSize > dest.length) {
throw new IllegalArgumentException("decodeUtf8 bounds invalid");
}
}
// call before Utf8Utils.decodeUtf8(...) Try / catch
try {
Utf8Utils.decodeUtf8(src, srcIdx, srcSize, dest, destIdx);
} catch (ArrayIndexOutOfBoundsException e) {
// bounds mismatch — recompute srcSize/dest allocation, do not retry blindly
throw new IllegalArgumentException("bad utf8 buffer bounds", e);
} Prevention
- Allocate destChars with length >= srcSize (safe upper bound).
- Validate length prefixes against the actual buffer before decoding.
- Keep serializer and deserializer versions aligned to avoid length-prefix drift.
When it happens
Trigger: decodeUtf8(srcBytes, srcIdx, srcSize, destChars, destIdx) is called with srcIdx<0, srcSize<0, srcIdx+srcSize>srcBytes.length, or destIdx+srcSize>destChars.length. This happens in Dubbo's serialization/deserialization path when a length prefix is corrupted or a destination buffer was sized too small for the declared UTF-8 byte count.
Common situations: Corrupt or truncated network payload where the declared length exceeds the actual buffer. A deserializer computed destChars length assuming all-ASCII (1 byte/char) but the data contains multi-byte sequences needing the same char count yet a mis-sized array. Version mismatch between serializer and deserializer producing wrong length prefixes. Manually slicing a byte array with wrong offsets.
Related errors
- invalid UTF-8.
- [Serialization Security] Serialized class {className} has no
- [Serialization Security] Serialized class {className} is not
- [Serialization Security] Serialized class {className} is in
- type [ ${type} ] is unsupported
AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14).
Data as JSON: /api/errors/e8819e0162d12d1a.
Report an issue: GitHub.