pxb1988/dex2jar · error · UTFDataFormatException

bad second or third byte

Error message

bad second or third byte

What it means

Thrown by Mutf8.decode when a lead byte indicated a 3-byte sequence (0xE0-0xEF) but either the second or third continuation byte is missing its 10xx xxxx pattern. The byte stream is not valid Modified UTF-8.

Solutions

  1. Verify the decode start offset is the byte after the ULEB128 length in string_data
  2. Re-obtain the DEX file; corruption is likely
  3. Catch UTFDataFormatException and skip/report the bad string index instead of failing the whole file

Example fix

null
Defensive patterns

Strategy: try-catch

Validate before calling

if ((b & 0xC0) != 0x80 || (c & 0xC0) != 0x80) return false; // pre-check continuation bytes for 3-byte sequences

Type guard

boolean isContinuation(int b) { return (b & 0xC0) == 0x80; }

Try / catch

try { return Mutf8.decode(buf, pos); } catch (UTFDataFormatException e) { throw new DexException("invalid string data at offset " + pos[0], e); }

Prevention

When it happens

Trigger: Decoding a DEX string where the 3-byte sequence bytes are corrupted, or the buffer position is misaligned so continuation bytes land on unrelated data.

Common situations: Corrupted DEX files, incorrect offset computation into string_data, mixed non-MUTF-8 encoders writing strings into DEX-like blobs.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of pxb1988/dex2jar@b5bda4fb49 (2026-09-08). Data as JSON: /api/errors/354066dfcdc8c670. Report an issue: GitHub.

Appendix: source

Thrown at dex-reader/src/main/java/com/googlecode/d2j/util/Mutf8.java:55

        while (true) {
            char a = (char) (in.get() & 0xff);
            if (a == 0) {
                return sb.toString();
            }

            if (a < '\u0080') {
                sb.append(a);
            } else if ((a & 0xe0) == 0xc0) {
                int b = in.get() & 0xff;
                if ((b & 0xC0) != 0x80) {
                    throw new UTFDataFormatException("bad second byte");
                }
                sb.append((char) (((a & 0x1F) << 6) | (b & 0x3F)));
            } else if ((a & 0xf0) == 0xe0) {
                int b = in.get() & 0xff;
                int c = in.get() & 0xff;
                if (((b & 0xC0) != 0x80) || ((c & 0xC0) != 0x80)) {
                    throw new UTFDataFormatException("bad second or third byte");
                }
                sb.append((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.
     */
    private 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;

View on GitHub (pinned to b5bda4fb49)