Tencent/tinker · error · UTFDataFormatException
bad byte
Error message
bad byte
What it means
Thrown by Mutf8.decode when the lead byte of a character is not < 0x80, not 0b110xxxxx, and not 0b1110xxxx — i.e. a bare continuation byte (0x80–0xBF) or an invalid 0xF0–0xFF byte where a lead byte was expected. MUTF-8 allows only 1-, 2-, and 3-byte forms.
Source
Thrown at third-party/aosp-dexutils/src/main/java/com/tencent/tinker/android/dex/Mutf8.java:58
}
out[s] = a;
if (a < '\u0080') {
s++;
} else if ((a & 0xe0) == 0xc0) {
int b = in.readByte() & 0xff;
if ((b & 0xC0) != 0x80) {
throw new UTFDataFormatException("bad second byte");
}
out[s++] = (char) (((a & 0x1F) << 6) | (b & 0x3F));
} else if ((a & 0xf0) == 0xe0) {
int b = in.readByte() & 0xff;
int c = in.readByte() & 0xff;
if (((b & 0xC0) != 0x80) || ((c & 0xC0) != 0x80)) {
throw new UTFDataFormatException("bad second or third byte");
}
out[s++] = (char) (((a & 0x0F) << 12) | ((b & 0x3F) << 6) | (c & 0x3F));
} else {
throw new UTFDataFormatException("bad byte");
}
}
}
/**
* Returns the number of bytes the modified UTF8 representation of 's' would take.
*/
public static long countBytes(String s, boolean shortLength) throws UTFDataFormatException {
long result = 0;
final int length = s.length();
for (int i = 0; i < length; ++i) {
char ch = s.charAt(i);
if (ch != 0 && ch <= 127) { // U+0000 uses two bytes.
++result;
} else if (ch <= 2047) {
result += 2;
} else {
result += 3;View on GitHub (pinned to 1b7ea02c23)
Solutions
- If you generate the dex, ensure supplementary characters (emoji, rare CJK) are written as surrogate pairs via Mutf8.encode, not as 4-byte UTF-8.
- Re-align: recompute the string_data_item offset from the string_ids table before decoding.
- If a length prefix (utf16_size) mismatch is possible, decode with an explicit length bound rather than until NUL.
Defensive patterns
Strategy: try-catch
Try / catch
catch (UTFDataFormatException e) -> quarantine the dex, log first 16 bytes at the failing offset for triage
Prevention
- If embedding unicode-heavy constants, verify the toolchain emits surrogate pairs (CESU-8 style), not 4-byte UTF-8.
- Unit-test your dex generation with supplementary-plane characters (emoji) to catch encoding path mismatches early.
When it happens
Trigger: The decode position lands mid-character (previous sequence consumed the wrong number of bytes), or the data contains raw 4-byte UTF-8 (standard Java UTF-8, not MUTF-8) or binary garbage in the string region.
Common situations: Strings written with standard UTF-8 (4-byte surrogates for supplementary chars) instead of MUTF-8's CESU-8-style surrogate pairs; buffer underflow reading past the string's declared length into unrelated bytes.
Related errors
- bad second byte
- bad second or third byte
- Declared length ${expectedLength} doesn't match decoded leng
- Unexpected type: ${type}
- invalid LEB128 sequence
AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14).
Data as JSON: /api/errors/d8200152ad73063f.
Report an issue: GitHub.