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
- Rebuild the offending dex with a mainstream toolchain (d8/dx) which always emits a map list.
- If the dex is a build intermediate, find the upstream step that stripped or never wrote mapList and disable that stripping.
- 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
- In build pipelines, always run the final dex through d8 (not just ART-loadable tooling) so map-less outputs are caught at build time.
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
- unknown section type: ${type}
- Unexpected magic: ${magic}
- Unexpected header: 0x${headerSize}
- Unexpected endian tag: 0x${endianTag}
- Unexpected map value for 0x${type}
AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14).
Data as JSON: /api/errors/e08345ea60513904.
Report an issue: GitHub.