Tencent/tinker · info · IOException

Size mismatch on inflated file: ${bytesRead} vs ${entry.size

Error message

Size mismatch on inflated file: ${bytesRead} vs ${entry.size}

What it means

IOException('Size mismatch on inflated file: <bytesRead> vs <entry.size>') also lives inside the commented-out ZipInflaterInputStream class (TinkerZipFile.java:569 onward) and is unreachable in this fork. Its original purpose: when the inflater reports EOF, compare the number of bytes actually inflated (bytesRead) with the uncompressed size recorded in the entry's metadata (entry.size); a mismatch means either the deflate stream or the size field is wrong. In the live code of this repository it can never be thrown.

Source

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

    /** @hide */
    /*public static class ZipInflaterInputStream extends InflaterInputStream {
        private final ZipEntry entry;
        private long bytesRead = 0;
        public ZipInflaterInputStream(InputStream is, Inflater inf, int bsize, ZipEntry entry) {
            super(is, inf, bsize);
            this.entry = entry;
        }
        @Override public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
            final int i;
            try {
                i = super.read(buffer, byteOffset, byteCount);
            } catch (IOException e) {
                throw new IOException("Error reading data for " + entry.getName() + " near offset "
                        + bytesRead, e);
            }
            if (i == -1) {
                if (entry.size != bytesRead) {
                    throw new IOException("Size mismatch on inflated file: " + bytesRead + " vs "
                            + entry.size);
                }
            } else {
                bytesRead += i;
            }
            return i;
        }
        @Override public int available() throws IOException {
            if (closed) {
                // Our superclass will throw an exception, but there's a jtreg test that
                // explicitly checks that the InputStream returned from ZipFile.getInputStream
                // returns 0 even when closed.
                return 0;
            }
            return super.available() == 0 ? 0 : (int) (entry.getSize() - bytesRead);
        }
    }*/
}

View on GitHub (pinned to 1b7ea02c23)

Solutions

  1. If hit on an AOSP-derived build: verify whether the deflate stream or the size field is wrong (inflate fully with an independent tool); usually the archive must be regenerated.
  2. Ensure any tool that rewrites entry contents also updates size/crc in the central directory and local headers.
  3. In this repository, no handling needed — dead code.
Defensive patterns

Strategy: try-catch

Try / catch

// only relevant on builds where ZipInflaterInputStream is enabled (not this fork)
try {
    readFully(in, expectedSize);
} catch (IOException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Size mismatch on inflated file")) {
        // metadata disagrees with actual inflated bytes — archive is inconsistent
        throw new IOException("Entry size metadata does not match data; rebuild archive", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: In builds where the class is active: reading an entry whose DEFLATE stream ends at a different byte count than the central directory's uncompressed-size field — truncated data, an entry recompressed without updating sizes, or a tampered size field. In this repository: unreachable.

Common situations: Hot-patch/zip-flushing tools that rewrite entry data but keep stale size metadata; partially downloaded archives; auditing logs from a build derived from AOSP's zip implementation.

Related errors


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