pxb1988/dex2jar · error · IOException

Size mismatch on inflated file: vs

Error message

Size mismatch on inflated file:  vs 

What it means

Thrown by the same wrapped entry stream when the entry inflates without error but at EOF the total bytes read (bytesRead) does not equal the entry's declared uncompressed size (entry.size). The library enforces the size contract from the zip directory against actual inflated output.

Solutions

  1. Rebuild the archive with a standards-compliant zip tool so entry sizes match the data.
  2. Check whether entry.size was populated from a local header with placeholder sizes (streaming entries) and use the central directory value instead.
  3. Catch this IOException and treat the entry as suspect; optionally consume via the raw inflater path if the data is known-good.
  4. Compare central directory offsets against actual file length to detect truncation.

Example fix

// before
try (InputStream in = zipFile.getInputStream(entry)) {
    in.transferTo(out); // throws 'Size mismatch on inflated file'
}
// after
try {
    try (InputStream in = zipFile.getInputStream(entry)) {
        in.transferTo(out);
    }
} catch (IOException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Size mismatch on inflated file")) {
        logger.warn("Entry size field inconsistent; treating entry as suspect", e);
    } else {
        throw e;
    }
}
Defensive patterns

Strategy: validation

Validate before calling

// Compare declared entry size against actual inflated bytes after reading
static boolean sizeConsistent(ZipEntry e, byte[] inflated) {
    return e.getSize() < 0 || e.getSize() == inflated.length;
}

Type guard

static boolean hasDeclaredSize(ZipEntry e) {
    return e != null && e.getSize() >= 0; // -1 = size unknown (streaming/data-descriptor entry)
}

Try / catch

try {
    try (InputStream in = zipFile.getInputStream(entry)) {
        in.transferTo(out);
    }
} catch (IOException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Size mismatch on inflated file")) {
        logger.warn("Declared size disagrees with inflated data; entry suspect: " + e.getMessage());
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Reading an entry to EOF (read() returning -1) where inflated byte count != entry.size: entries written with wrong/placeholder size fields (streaming zip writers using data descriptors), manually patched archives, or non-standard repackaging tools.

Common situations: Archives built by streaming compressors that store 0/placeholder sizes in headers; apks/jars repackaged by non-compliant tools; truncated or appended-to archives.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


AI-assisted analysis of pxb1988/dex2jar@b5bda4fb49 (2026-09-08). Data as JSON: /api/errors/6a4c42b2e030aef2. Report an issue: GitHub.

Appendix: source

Thrown at dex-reader/src/main/java/com/googlecode/d2j/util/zip/ZipFile.java:299

        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 {
            return super.available() == 0 ? 0 : (int) (entry.getSize() - bytesRead);
        }
    }

    private static class ByteBufferBackedInputStream extends InputStream {
        private final ByteBuffer buf;

        public ByteBufferBackedInputStream(ByteBuffer buf) {
            this.buf = buf;

View on GitHub (pinned to b5bda4fb49)