Tencent/tinker · error · DexException

Cannot merge dex files that do not contain a map

Error message

Cannot merge dex files that do not contain a map

What it means

Thrown by TableOfContents.readHeader when map_off (the map_list file offset at header offset 52) is 0. The message text ('Cannot merge dex files that do not contain a map') reveals the primary consumer: dex merging needs the map list to enumerate sections; without it the table of contents cannot be built.

Source

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

            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();
        classDefs.off = headerIn.readInt();
        dataSize = headerIn.readInt();
        dataOff = headerIn.readInt();
    }

    private void readMap(Dex.Section in) throws IOException {

View on GitHub (pinned to 1b7ea02c23)

Solutions

  1. Rebuild the offending dex with a mainstream toolchain (d8/dx) which always emits a map list.
  2. If the dex is a build intermediate, find the upstream step that stripped or never wrote mapList and disable that stripping.
  3. As a diagnostic, hexdump offset 52 — if it's zero while other header fields look sane, the file was post-processed.
Defensive patterns

Strategy: try-catch

Validate before calling

static boolean hasMapList(ByteBuffer b) { return b.getInt(52) != 0; } // map_off

Try / catch

catch (DexException e) with 'do not contain a map' -> rebuild the dex with d8; do not attempt merge of map-less inputs

Prevention

When it happens

Trigger: new Dex()/TableOfContents.readFrom on a dex whose map_off was zeroed — typically produced by nonstandard writers (some proguard/older dx edge cases, stripped dexes) or by patch tools that rewrite the header and clear map_off.

Common situations: Dexes that load fine on ART (the runtime is lazier about the map) but fail Tinker-style patch generation, which fully parses the TOC; header corruption after binary edits.

Related errors


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