apache/dubbo · error · IllegalArgumentException
invalid UTF-8.
Error message
invalid UTF-8.
What it means
Thrown by Utf8Utils.decodeUtf8 when a leading byte signals a 2-byte UTF-8 sequence (0xC2..0xDF) but the buffer ends before the continuation byte arrives (offset>=limit). It is a truncation error: the multi-byte sequence is incomplete at the end of srcSize.
Source
Thrown at dubbo-common/src/main/java/org/apache/dubbo/common/utils/Utf8Utils.java:88
}
while (offset < limit) {
byte byte1 = srcBytes[offset++];
if (DecodeUtil.isOneByte(byte1)) {
DecodeUtil.handleOneByteSafe(byte1, destChars, destIdx++);
// It's common for there to be multiple ASCII characters in a run mixed in, so add an
// extra optimized loop to take care of these runs.
while (offset < limit) {
byte b = srcBytes[offset];
if (!DecodeUtil.isOneByte(b)) {
break;
}
offset++;
DecodeUtil.handleOneByteSafe(b, destChars, destIdx++);
}
} else if (DecodeUtil.isTwoBytes(byte1)) {
if (offset >= limit) {
throw new IllegalArgumentException("invalid UTF-8.");
}
DecodeUtil.handleTwoBytesSafe(byte1, /* byte2 */ srcBytes[offset++], destChars, destIdx++);
} else if (DecodeUtil.isThreeBytes(byte1)) {
if (offset >= limit - 1) {
throw new IllegalArgumentException("invalid UTF-8.");
}
DecodeUtil.handleThreeBytesSafe(
byte1,
/* byte2 */ srcBytes[offset++],
/* byte3 */ srcBytes[offset++],
destChars,
destIdx++);
} else {
if (offset >= limit - 2) {
throw new IllegalArgumentException("invalid UTF-8.");
}
DecodeUtil.handleFourBytesSafe(
byte1,View on GitHub (pinned to 3a3043227f)
Solutions
- Confirm srcSize matches the true byte length of the encoded string (re-read the length prefix and the full buffer).
- Ensure the source buffer is not truncated; reassemble frames before decoding.
- Validate the payload with a standard CharsetDecoder (UTF_8) to locate the truncation point.
- If you control the wire format, write byte-length prefixes and read exactly that many bytes before decoding.
Example fix
// before // reader consumed asciiLen chars worth then decoded, truncating last multibyte char Utf8Utils.decodeUtf8(buf, off, asciiLen, out, 0); // after // use the exact declared byte length from the stream Utf8Utils.decodeUtf8(buf, off, declaredByteLen, out, 0);
Defensive patterns
Strategy: validation
Validate before calling
boolean isCompleteUtf8(byte[] b, int off, int len) {
int end = off + len, i = off;
while (i < end) {
int c = b[i] & 0xFF;
int need;
if (c < 0x80) need = 0;
else if ((c >> 5) == 0x6) need = 1;
else if ((c >> 4) == 0xE) need = 2;
else if ((c >> 3) == 0x1E) need = 3;
else return false;
if (i + need >= end) return false; // truncated
i += 1 + need;
}
return true;
} Try / catch
try {
Utf8Utils.decodeUtf8(src, off, len, out, 0);
} catch (IllegalArgumentException e) {
if ("invalid UTF-8.".equals(e.getMessage())) { /* truncated/invalid — re-read frame */ }
throw e;
} Prevention
- Buffer complete frames before UTF-8 decoding.
- Use byte-accurate length prefixes on the wire, never char counts.
- Validate payload completeness with a UTF-8 CharsetDecoder in tests.
When it happens
Trigger: During deserialization, srcSize cuts off exactly after a 2-byte leading byte with no room for its continuation byte. Caused by a truncated payload, an off-by-one in length calculation, or a length prefix that under-counts the bytes of a multi-byte character.
Common situations: Network read returned a partial frame. A substring/slice operation split a multi-byte character at the boundary. A serializer wrote a UTF-8 string length in bytes but the reader interpreted it as char count and stopped early. Payload corruption truncating the last character.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- buffer srcBytes.length=%d, srcIdx=%d, srcSize=%d, destChars.
- [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/30fb9bd758ce3046.
Report an issue: GitHub.