Tencent/tinker · error · ZipException

End Of Central Directory signature not found

Error message

End Of Central Directory signature not found

What it means

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.

Source

Thrown at third-party/tinker-ziputils/src/main/java/com/tencent/tinker/ziputils/ziputil/TinkerZipFile.java:444

        final int headerMagic = Integer.reverseBytes(raf.readInt());
        if (headerMagic != LOCSIG) {
            throw new ZipException("Not a zip archive");
        }

        long stopOffset = scanOffset - 65536;
        if (stopOffset < 0) {
            stopOffset = 0;
        }

        while (true) {
            raf.seek(scanOffset);
            if (Integer.reverseBytes(raf.readInt()) == ENDSIG) {
                break;
            }

            scanOffset--;
            if (scanOffset < stopOffset) {
                throw new ZipException("End Of Central Directory signature not found");
            }
        }

        // Read the End Of Central Directory. ENDHDR includes the signature bytes,
        // which we've already read.
        byte[] eocd = new byte[ENDHDR - 4];
        raf.readFully(eocd);

        // Pull out the information we need.
        BufferIterator it = HeapBufferIterator.iterator(eocd, 0, eocd.length, ByteOrder.LITTLE_ENDIAN);
        int diskNumber = it.readShort() & 0xffff;
        int diskWithCentralDir = it.readShort() & 0xffff;
        int numEntries = it.readShort() & 0xffff;
        int totalNumEntries = it.readShort() & 0xffff;
        it.skip(4); // Ignore centralDirSize.
        long centralDirOffset = ((long) it.readInt()) & 0xffffffffL;
        int commentLength = it.readShort() & 0xffff;

View on GitHub (pinned to 1b7ea02c23)

Solutions

  1. Verify the file size against the expected total (Content-Length, checksum) and re-download if it is short.
  2. 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'.
  3. For files you generate, ensure nothing is appended after the zip comment; keep comments < 64 KiB.

Example fix

// before
TinkerZipFile zf = new TinkerZipFile(new File(patchPath)); // truncated download

// after
long expected = downloader.expectedSize(patchUrl);
File f = new File(patchPath);
if (f.length() != expected) {
    downloader.refetch(patchUrl, f);
}
TinkerZipFile zf = new TinkerZipFile(f);
Defensive patterns

Strategy: validation

Validate before calling

// cheapest reliable guard: compare against expected total size / checksum
if (expectedBytes != null && file.length() != expectedBytes) {
    throw new IOException("Truncated archive: " + file.length() + " of " + expectedBytes + " bytes");
}
TinkerZipFile zf = new TinkerZipFile(file);

Try / catch

try {
    zf = new TinkerZipFile(file);
} catch (ZipException e) {
    if (e.getMessage().contains("End Of Central Directory signature not found")) {
        throw new IOException("Archive truncated or damaged (no EOCD): re-download " + file, e);
    }
    throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14). Data as JSON: /api/errors/50ff2b6fa75822c3. Report an issue: GitHub.