Tencent/tinker · error · ZipException

STORED entry missing CRC

Error message

STORED entry missing CRC

What it means

For STORED (uncompressed) entries the zip format stores the CRC in the local header before the data, so the writer cannot compute it on the fly. putNextEntry() therefore throws ZipException("STORED entry missing CRC") when the entry's method resolves to STORED and ze.getCrc() == -1. Note that -1 is also the value CRC32 computed for empty input would never legitimately produce, so it doubles as the 'unset' sentinel.

Source

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

     */
    public void putNextEntry(TinkerZipEntry ze) throws IOException {
        if (currentEntry != null) {
            closeEntry();
        }
        // Did this ZipEntry specify a method, or should we use the default?
        int method = ze.getMethod();
        if (method == -1) {
            method = defaultCompressionMethod;
        }
        // If the method is STORED, check that the ZipEntry was configured appropriately.
        if (method == STORED) {
            if (ze.getCompressedSize() == -1) {
                ze.setCompressedSize(ze.getSize());
            } else if (ze.getSize() == -1) {
                ze.setSize(ze.getCompressedSize());
            }
            if (ze.getCrc() == -1) {
                throw new ZipException("STORED entry missing CRC");
            }
            if (ze.getSize() == -1) {
                throw new ZipException("STORED entry missing size");
            }
            if (ze.size != ze.compressedSize) {
                throw new ZipException("STORED entry size/compressed size mismatch");
            }
        }
        checkOpen();
        // checkAndSetZip64Requirements(ze);

        //zhangshaowen edit here, we just want the same time and modDate
        ze.comment = null;
        ze.extra = null;
        ze.time = TIME_CONST;
        ze.modDate = MOD_DATE_CONST;

        nameBytes = ze.name.getBytes(StandardCharsets.UTF_8);

View on GitHub (pinned to 1b7ea02c23)

Solutions

  1. Compute the CRC32 of the entry data first and call ze.setCrc(crc.getValue()) before putNextEntry().
  2. Also set ze.setSize(len) and ze.setCompressedSize(len) (they must be equal for STORED) to avoid the follow-up exceptions at lines 464/467.
  3. If you cannot precompute sizes (streaming data of unknown length), use DEFLATED instead of STORED.

Example fix

// before
TinkerZipEntry e = new TinkerZipEntry("res.bin");
e.setMethod(TinkerZipEntry.STORED);
zos.putNextEntry(e); // throws: missing CRC

// after
byte[] data = Files.readAllBytes(path);
CRC32 crc = new CRC32();
crc.update(data);
TinkerZipEntry e = new TinkerZipEntry("res.bin");
e.setMethod(TinkerZipEntry.STORED);
e.setCrc(crc.getValue());
e.setSize(data.length);
e.setCompressedSize(data.length);
zos.putNextEntry(e);
zos.write(data);
Defensive patterns

Strategy: validation

Validate before calling

void putStored(TinkerZipOutputStream zos, String name, byte[] data) throws IOException {
    if (data == null) throw new IllegalArgumentException("data null for " + name);
    CRC32 crc = new CRC32();
    crc.update(data);
    TinkerZipEntry e = new TinkerZipEntry(name);
    e.setMethod(TinkerZipEntry.STORED);
    e.setCrc(crc.getValue());
    e.setSize(data.length);
    e.setCompressedSize(data.length);
    zos.putNextEntry(e);
    zos.write(data, 0, data.length);
    zos.closeEntry();
}

Prevention

When it happens

Trigger: Calling putNextEntry(entry) where entry.setMethod(TinkerZipEntry.STORED) (or the stream's defaultCompressionMethod was set to STORED) without first calling entry.setCrc(...) with a computed CRC32 value.

Common situations: Switching a repack pipeline from DEFLATED to STORED to make entries byte-identical (common in Tinker/Android patch tooling to keep alignment) but forgetting that STORED requires precomputed crc, size, and compressedSize; copying entries from another zip without copying their crc field.

Related errors


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