{"record":{"id":"914e593bed5058d6","repo":"Tencent/tinker","slug":"unexpected-magic-magic","errorCode":null,"errorMessage":"Unexpected magic: ${magic}","messagePattern":"Unexpected magic: (.+?)","errorType":"exception","errorClass":"DexException","httpStatus":null,"severity":"error","filePath":"third-party/aosp-dexutils/src/main/java/com/tencent/tinker/android/dex/TableOfContents.java","lineNumber":170,"sourceCode":"        }\n    }\n\n    public void readFrom(Dex dex) throws IOException {\n        readHeader(dex.openSection(header));\n        // special case, since mapList.byteCount is available only after\n        // computeSizesFromOffsets() was invoked, so here we can't use\n        // dex.openSection(mapList) to get dex section. Or\n        // 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\");","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/Tencent/tinker/blob/1b7ea02c239840f563ea64fb5bd286eb98d4011e/third-party/aosp-dexutils/src/main/java/com/tencent/tinker/android/dex/TableOfContents.java#L152-L188","documentation":"Thrown by TableOfContents.readHeader when the first 8 bytes are not a recognized dex magic (\"dex\\n035\\0\" style, validated via DexFormat.magicToApi returning -1). The magic both identifies the format and encodes the version; anything unparseable is rejected before any other header field is read.","triggerScenarios":"new Dex(bytes) or dex merging where the input is not a raw dex: a compact-dex (cdex, magic \"cdex001\"—ART on-device layout), a zip passed as bytes, an ELF/.odex, or a truncated file missing the header.","commonSituations":"Pointing the tool at build outputs of the wrong artifact type (apks containing compact dex from Android 8.1+ build tooling), extracted odex/vdex files, or empty/HTML error pages saved with a .dex name.","solutions":["Confirm the input really is a standard dex: hexdump the first 8 bytes and compare to \"dex\\n035\\0\" (or 036/037/038).","If the artifact is a compact dex, convert it back: use the toolchain's conversion (e.g. `dexdump`/profgen or d8 with the extracted dex) or extract the original dex from the apk instead of on-device artifacts.","Skip non-dex files in batch pipelines by checking the magic before handing the buffer to Dex."],"exampleFix":"// before\nDex dex = new Dex(new File(dir, name)); // blows up on odex/cdex\n\n// after\nbyte[] head = new byte[8];\ntry (RandomAccessFile raf = new RandomAccessFile(f, \"r\")) {\n    raf.readFully(head);\n}\nif (!new String(head, StandardCharsets.US_ASCII).startsWith(\"dex\\n\")) continue;\nDex dex = new Dex(f);","handlingStrategy":"validation","validationCode":"static boolean isStandardDex(byte[] head8) {\n    return head8 != null && head8.length >= 4 && head8[0]=='d' && head8[1]=='e' && head8[2]=='x' && head8[3]=='\\n';\n}\n// use before new Dex(...): read 8 bytes, reject cdex/odex/non-dex","typeGuard":null,"tryCatchPattern":"catch (DexException e) with 'Unexpected magic' -> skip file in batch runs, or convert compact-dex source before retry","preventionTips":["Filter build artifacts by magic bytes, not file extension, before dex processing.","Extract dex from apks on the build machine rather than pulling odex/vdex from devices."],"tags":["dex","magic","header","compact-dex","tinker"],"backgroundTag":null,"analyzedSha":"1b7ea02c239840f563ea64fb5bd286eb98d4011e","analyzedAt":"2026-08-14T15:16:52.110Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}