{"record":{"id":"a96050a45cd30f7c","repo":"Tencent/tinker","slug":"unexpected-header-0x-headersize","errorCode":null,"errorMessage":"Unexpected header: 0x${headerSize}","messagePattern":"Unexpected header: 0x(.+?)","errorType":"exception","errorClass":"DexException","httpStatus":null,"severity":"error","filePath":"third-party/aosp-dexutils/src/main/java/com/tencent/tinker/android/dex/TableOfContents.java","lineNumber":178,"sourceCode":"        // an {@code java.nio.BufferUnderflowException} will be thrown.\n        readMap(dex.openSection(mapList.off));\n        computeSizesFromOffsets();\n    }\n\n    private void readHeader(Dex.Section headerIn) throws UnsupportedEncodingException {\n        byte[] magic = headerIn.readByteArray(8);\n        api = DexFormat.magicToApi(magic);\n\n        if (api == -1) {\n            throw new DexException(\"Unexpected magic: \" + Arrays.toString(magic));\n        }\n\n        checksum = headerIn.readInt();\n        signature = headerIn.readByteArray(20);\n        fileSize = headerIn.readInt();\n        int headerSize = headerIn.readInt();\n        if (headerSize != SizeOf.HEADER_ITEM) {\n            throw new DexException(\"Unexpected header: 0x\" + Integer.toHexString(headerSize));\n        }\n        int endianTag = headerIn.readInt();\n        if (endianTag != DexFormat.ENDIAN_TAG) {\n            throw new DexException(\"Unexpected endian tag: 0x\" + Integer.toHexString(endianTag));\n        }\n        linkSize = headerIn.readInt();\n        linkOff = headerIn.readInt();\n        mapList.off = headerIn.readInt();\n        if (mapList.off == 0) {\n            throw new DexException(\"Cannot merge dex files that do not contain a map\");\n        }\n        stringIds.size = headerIn.readInt();\n        stringIds.off = headerIn.readInt();\n        typeIds.size = headerIn.readInt();\n        typeIds.off = headerIn.readInt();\n        protoIds.size = headerIn.readInt();\n        protoIds.off = headerIn.readInt();\n        fieldIds.size = headerIn.readInt();","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/Tencent/tinker/blob/1b7ea02c239840f563ea64fb5bd286eb98d4011e/third-party/aosp-dexutils/src/main/java/com/tencent/tinker/android/dex/TableOfContents.java#L160-L196","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"static boolean plausibleDexHeader(ByteBuffer b) {\n    return b.getInt(36) == 0x70; // header_size\n}","typeGuard":null,"tryCatchPattern":"catch (DexException e) -> treat as corrupt input; re-obtain from source of truth, never patch header_size to pass","preventionTips":["Protect dex artifacts with checksums/signatures end-to-end through your patch pipeline.","Never binary-edit dex headers with ad-hoc scripts."],"tags":["dex","header","validation","corruption","tinker"],"backgroundTag":null,"analyzedSha":"1b7ea02c239840f563ea64fb5bd286eb98d4011e","analyzedAt":"2026-08-14T15:16:52.110Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}