Tencent/tinker · error · DexException
Unexpected header: 0x${headerSize}
Error message
Unexpected header: 0x${headerSize} What it means
Thrown by TableOfContents.readHeader when header_size (offset 36) does not equal SizeOf.HEADER_ITEM (0x70). The dex spec fixes the header item at 112 bytes; a different value means the layout this parser assumes does not match the file, so every subsequent fixed-offset read would be wrong.
Source
Thrown at third-party/aosp-dexutils/src/main/java/com/tencent/tinker/android/dex/TableOfContents.java:178
// an {@code java.nio.BufferUnderflowException} will be thrown.
readMap(dex.openSection(mapList.off));
computeSizesFromOffsets();
}
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();View on GitHub (pinned to 1b7ea02c23)
Solutions
- Verify integrity via the header checksum/SHA-1; a mismatch confirms corruption — restore from a clean source.
- Rebuild the dex from sources/classes with a standard toolchain (d8) rather than repairing the binary.
- Reject such files early in pipelines instead of trying to merge them.
Defensive patterns
Strategy: try-catch
Validate before calling
static boolean plausibleDexHeader(ByteBuffer b) {
return b.getInt(36) == 0x70; // header_size
} Try / catch
catch (DexException e) -> treat as corrupt input; re-obtain from source of truth, never patch header_size to pass
Prevention
- Protect dex artifacts with checksums/signatures end-to-end through your patch pipeline.
- Never binary-edit dex headers with ad-hoc scripts.
When it happens
Trigger: Reading a file that passed the magic check but has a nonstandard header — patched binaries where someone rewrote the magic, experimental formats, or a header-size field corrupted by partial writes.
Common situations: Rare in practice; most often seen after binary-level tampering, badly applied hot-patch tooling that edits headers in place, or when a zip-local-file artifact coincidentally starts with dex-like bytes.
Related errors
- Unexpected endian tag: 0x${endianTag}
- Unexpected type: ${type}
- Unexpected magic: ${magic}
- Cannot merge dex files that do not contain a map
- Unexpected map value for 0x${type}
AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14).
Data as JSON: /api/errors/a96050a45cd30f7c.
Report an issue: GitHub.