Tencent/tinker · error · ZipException
CRC mismatch
Error message
CRC mismatch
What it means
For STORED (uncompressed) zip entries, AlignedZipOutputStream requires the caller to pre-compute and declare both CRC and size on the ZipEntry before writing, because STORED data is copied verbatim and must be self-describing. closeEntry() compares the CRC of the bytes actually written (maintained in this.crc) against currentEntry.getCrc(); any difference throws 'CRC mismatch'. This mirrors java.util.zip.ZipOutputStream's behavior for STORED entries.
Source
Thrown at third-party/tinker-ziputils/src/main/java/com/tencent/tinker/ziputils/ziputil/AlignedZipOutputStream.java:155
* Closes the current {@code ZipEntry}. Any entry terminal data is written
* to the underlying stream.
*
* @throws IOException
* If an error occurs closing the entry.
*/
public void closeEntry() throws IOException {
checkOpen();
if (currentEntry == null) {
return;
}
if (currentEntry.getMethod() == DEFLATED) {
super.finish();
}
// Verify values for STORED types
if (currentEntry.getMethod() == STORED) {
if (crc.getValue() != currentEntry.getCrc()) {
throw new ZipException("CRC mismatch");
}
if (currentEntry.getSize() != crcDataSize) {
throw new ZipException("Size mismatch");
}
}
int curOffset = LOCHDR;
// Write the DataDescriptor
if (currentEntry.getMethod() != STORED) {
curOffset += EXTHDR;
writeLong(out, EXTSIG);
currentEntry.setCrc(crc.getValue());
writeLong(out, currentEntry.getCrc());
currentEntry.setCompressedSize(def.getTotalOut());
writeLong(out, currentEntry.getCompressedSize());
currentEntry.setSize(def.getTotalIn());
writeLong(out, currentEntry.getSize());
View on GitHub (pinned to 1b7ea02c23)
Solutions
- Before writing a STORED entry, compute the CRC over the exact bytes you will write: byte[] data = ...; crc.reset(); crc.update(data); entry.setCrc(crc.getValue()); entry.setSize(data.length); entry.setCompressedSize(data.length).
- When cloning entries from a source zip, stream the entry bytes and recompute size/CRC yourself instead of trusting the source entry's metadata if the content may differ.
- If sizes/CRCs are not known up front, use DEFLATED (the stream writes a data descriptor and computes values for you) or buffer the content first.
Example fix
// before: STORED entry with stale/absent CRC
zos.putNextEntry(new ZipEntry("assets/blob.bin")); // method defaults may be STORED
zos.write(data); // closeEntry() throws CRC mismatch
// after: declare exact size and CRC for STORED data
CRC32 crc = new CRC32();
crc.update(data);
ZipEntry e = new ZipEntry("assets/blob.bin");
e.setMethod(ZipEntry.STORED);
e.setSize(data.length);
e.setCompressedSize(data.length);
e.setCrc(crc.getValue());
zos.putNextEntry(e);
zos.write(data); Defensive patterns
Strategy: validation
Validate before calling
// Precompute size+CRC for STORED entries before putNextEntry
java.util.zip.CRC32 crc = new java.util.zip.CRC32();
crc.update(data);
if (entry.getMethod() == java.util.zip.ZipEntry.STORED
&& (entry.getCrc() != crc.getValue() || entry.getSize() != data.length)) {
entry.setSize(data.length);
entry.setCompressedSize(data.length);
entry.setCrc(crc.getValue());
} Try / catch
try {
zos.closeEntry();
} catch (java.util.zip.ZipException e) {
if ("CRC mismatch".equals(e.getMessage())) {
throw new IllegalStateException("STORED entry " + entry.getName() + " declared a CRC that does not match written bytes", e);
}
throw e;
} Prevention
- Always buffer STORED content and set size, compressedSize, and CRC from the exact payload before putNextEntry.
- Prefer DEFLATED when content metadata is not known up front.
- When cloning entries from another zip, recompute CRC/size instead of copying the source entry's values.
When it happens
Trigger: putNextEntry(new ZipEntry(name)) with method STORED and a setCrc() value that does not match the bytes subsequently written via write(); or forgetting to set the CRC on an entry copied from another zip after modifying its content.
Common situations: Copying entries between zips (tinker patch building, re-aligning APKs) and keeping the source entry's CRC while writing different bytes; computing CRC over the wrong byte range (e.g. including/excluding a padding byte); using STORED with data whose size/CRC are only known after compression elsewhere.
Related errors
- STORED entry missing CRC
- Size mismatch
- Bad CRC32: ${value}
- STORED entry missing size
- STORED entry size/compressed size mismatch
AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14).
Data as JSON: /api/errors/f53ca4e465ffd085.
Report an issue: GitHub.