Tencent/tinker · error · UTFDataFormatException

bad second byte

Error message

bad second byte

What it means

Thrown by Mutf8.decode when decoding a 2-byte MUTF-8 sequence whose second byte is not a 0b10xxxxxx continuation. In MUTF-8 (dex string encoding), bytes 0xC0–0xDF lead a 2-byte char and the next byte must be 0x80–0xBF; anything else is malformed.

Source

Thrown at third-party/aosp-dexutils/src/main/java/com/tencent/tinker/android/dex/Mutf8.java:47

    /**
     * Decodes bytes from {@code in} into {@code out} until a delimiter 0x00 is
     * encountered. Returns a new string containing the decoded characters.
     */
    public static String decode(ByteInput in, char[] out) throws UTFDataFormatException {
        int s = 0;
        while (true) {
            char a = (char) (in.readByte() & 0xff);
            if (a == 0) {
                return new String(out, 0, s);
            }
            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.
     */

View on GitHub (pinned to 1b7ea02c23)

Solutions

  1. Validate the dex header checksum/signature; if it fails, the string data is corrupt — obtain a clean copy.
  2. If you produce the dex with custom tooling, encode strings with Mutf8.encode (or a spec-conformant encoder) rather than java.lang.String.getBytes(UTF-8).
  3. Cross-check with baksmali — if baksmali decodes fine, your reader's offset is wrong, not the data.
Defensive patterns

Strategy: try-catch

Try / catch

try { String s = Mutf8.decode(in, utf16Len); } catch (UTFDataFormatException e) { mark dex as unusable and fall back to a placeholder string with its id logged; never continue parsing mid-string }

Prevention

When it happens

Trigger: Decoding a dex string_id's MUTF-8 data where a 2-byte sequence's continuation byte was corrupted, or where the string bytes were written by a buggy encoder (or a buffer read started one byte into a multi-byte char).

Common situations: Corrupted dex string data from bad patching or partial writes; third-party string obfuscation/encryption tools that mangle MUTF-8; reading a dex buffer with the wrong offset into string_data_item.

Related errors


AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14). Data as JSON: /api/errors/b276666bd8f165e0. Report an issue: GitHub.