Tencent/tinker · error · DexException

Unexpected endian tag: 0x${endianTag}

Error message

Unexpected endian tag: 0x${endianTag}

What it means

Thrown by TableOfContents.readHeader when the endian_tag (offset 40) is not DexFormat.ENDIAN_TAG (0x12345678). The dex format is little-endian-only in practice; the tag exists to catch byte-order confusion, and a wrong value usually means every int in the file is swapped relative to expectation.

Source

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

    private void readHeader(Dex.Section headerIn) throws UnsupportedEncodingException {
        byte[] magic = headerIn.readByteArray(8);
        api = DexFormat.magicToApi(magic);

        if (api == -1) {
            throw new DexException("Unexpected magic: " + Arrays.toString(magic));
        }

        checksum = headerIn.readInt();
        signature = headerIn.readByteArray(20);
        fileSize = headerIn.readInt();
        int headerSize = headerIn.readInt();
        if (headerSize != SizeOf.HEADER_ITEM) {
            throw new DexException("Unexpected header: 0x" + Integer.toHexString(headerSize));
        }
        int endianTag = headerIn.readInt();
        if (endianTag != DexFormat.ENDIAN_TAG) {
            throw new DexException("Unexpected endian tag: 0x" + Integer.toHexString(endianTag));
        }
        linkSize = headerIn.readInt();
        linkOff = headerIn.readInt();
        mapList.off = headerIn.readInt();
        if (mapList.off == 0) {
            throw new DexException("Cannot merge dex files that do not contain a map");
        }
        stringIds.size = headerIn.readInt();
        stringIds.off = headerIn.readInt();
        typeIds.size = headerIn.readInt();
        typeIds.off = headerIn.readInt();
        protoIds.size = headerIn.readInt();
        protoIds.off = headerIn.readInt();
        fieldIds.size = headerIn.readInt();
        fieldIds.off = headerIn.readInt();
        methodIds.size = headerIn.readInt();
        methodIds.off = headerIn.readInt();
        classDefs.size = headerIn.readInt();

View on GitHub (pinned to 1b7ea02c23)

Solutions

  1. Checksum-validate; if invalid, replace the file — do not attempt to byte-swap dexes back.
  2. If you author dexes programmatically, write ENDIAN_TAG (0x12345678) little-endian at offset 40; compare against a d8-produced reference dex.
  3. Add an early magic+tag sanity filter to batch inputs.
Defensive patterns

Strategy: try-catch

Validate before calling

static boolean littleEndianTagOk(ByteBuffer b) { return b.getInt(40) == 0x12345678; }

Try / catch

catch (DexException e) with 'Unexpected endian tag' -> classify corrupt; re-download/rebuild the artifact

Prevention

When it happens

Trigger: Reading a dex that was byte-swapped by a big-endian intermediary, a header written by a buggy custom generator, or (most commonly) a corrupt/garbage file that happened to pass the magic and header-size checks.

Common situations: Corruption cases dominate; occasionally custom build tooling that assembles headers field-by-field gets the tag wrong, or truncated files where reads land on unrelated bytes.

Related errors


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