{"record":{"id":"50ff2b6fa75822c3","repo":"Tencent/tinker","slug":"end-of-central-directory-signature-not-found","errorCode":null,"errorMessage":"End Of Central Directory signature not found","messagePattern":"End Of Central Directory signature not found","errorType":"exception","errorClass":"ZipException","httpStatus":null,"severity":"error","filePath":"third-party/tinker-ziputils/src/main/java/com/tencent/tinker/ziputils/ziputil/TinkerZipFile.java","lineNumber":444,"sourceCode":"        final int headerMagic = Integer.reverseBytes(raf.readInt());\n        if (headerMagic != LOCSIG) {\n            throw new ZipException(\"Not a zip archive\");\n        }\n\n        long stopOffset = scanOffset - 65536;\n        if (stopOffset < 0) {\n            stopOffset = 0;\n        }\n\n        while (true) {\n            raf.seek(scanOffset);\n            if (Integer.reverseBytes(raf.readInt()) == ENDSIG) {\n                break;\n            }\n\n            scanOffset--;\n            if (scanOffset < stopOffset) {\n                throw new ZipException(\"End Of Central Directory signature not found\");\n            }\n        }\n\n        // Read the End Of Central Directory. ENDHDR includes the signature bytes,\n        // which we've already read.\n        byte[] eocd = new byte[ENDHDR - 4];\n        raf.readFully(eocd);\n\n        // Pull out the information we need.\n        BufferIterator it = HeapBufferIterator.iterator(eocd, 0, eocd.length, ByteOrder.LITTLE_ENDIAN);\n        int diskNumber = it.readShort() & 0xffff;\n        int diskWithCentralDir = it.readShort() & 0xffff;\n        int numEntries = it.readShort() & 0xffff;\n        int totalNumEntries = it.readShort() & 0xffff;\n        it.skip(4); // Ignore centralDirSize.\n        long centralDirOffset = ((long) it.readInt()) & 0xffffffffL;\n        int commentLength = it.readShort() & 0xffff;\n","sourceCodeStart":426,"sourceCodeEnd":462,"githubUrl":"https://github.com/Tencent/tinker/blob/1b7ea02c239840f563ea64fb5bd286eb98d4011e/third-party/tinker-ziputils/src/main/java/com/tencent/tinker/ziputils/ziputil/TinkerZipFile.java#L426-L462","documentation":"To find the End Of Central Directory record, readCentralDir scans backwards one byte at a time over at most the last 65536+ENDHDR bytes (the maximum zip comment length). If no ENDSIG ('PK\\x05\\x06') is found before hitting stopOffset, it throws ZipException('End Of Central Directory signature not found'). The usual cause is truncation: the EOCD lives at the very end of a zip, so a cut-off tail loses it.","triggerScenarios":"Opening a zip whose final <=64 KiB contains no EOCD signature — truncated downloads (missing final bytes), files truncated to a fixed size (FAT 4 GiB limit, transfer cap), or a central directory larger than the scan window combined with a comment-sized gap.","commonSituations":"Interrupted downloads of large APK/patch files; copying a zip onto a filesystem with a smaller file-size ceiling; some binary-patching tools appending data after the comment so the EOCD moves outside the scanned window.","solutions":["Verify the file size against the expected total (Content-Length, checksum) and re-download if it is short.","If you have the original, compare sizes to confirm truncation; if only the comment area is damaged, strip the trailing bytes and attempt recovery with 'zip -FF'.","For files you generate, ensure nothing is appended after the zip comment; keep comments < 64 KiB."],"exampleFix":"// before\nTinkerZipFile zf = new TinkerZipFile(new File(patchPath)); // truncated download\n\n// after\nlong expected = downloader.expectedSize(patchUrl);\nFile f = new File(patchPath);\nif (f.length() != expected) {\n    downloader.refetch(patchUrl, f);\n}\nTinkerZipFile zf = new TinkerZipFile(f);","handlingStrategy":"validation","validationCode":"// cheapest reliable guard: compare against expected total size / checksum\nif (expectedBytes != null && file.length() != expectedBytes) {\n    throw new IOException(\"Truncated archive: \" + file.length() + \" of \" + expectedBytes + \" bytes\");\n}\nTinkerZipFile zf = new TinkerZipFile(file);","typeGuard":null,"tryCatchPattern":"try {\n    zf = new TinkerZipFile(file);\n} catch (ZipException e) {\n    if (e.getMessage().contains(\"End Of Central Directory signature not found\")) {\n        throw new IOException(\"Archive truncated or damaged (no EOCD): re-download \" + file, e);\n    }\n    throw e;\n}","preventionTips":["Always checksum/size-verify downloads of zip artifacts before processing.","Do not append data after a zip's comment when generating archives.","Watch for filesystem file-size ceilings (e.g. 4 GiB on FAT32) when moving large zips."],"tags":["zip","truncation","eocd","tinker"],"backgroundTag":null,"analyzedSha":"1b7ea02c239840f563ea64fb5bd286eb98d4011e","analyzedAt":"2026-08-14T15:16:52.110Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}