pxb1988/dex2jar · error · IOException

Error reading data for near offset

Error message

Error reading data for  near offset 

What it means

Thrown by the ZipEntryInputStream.read() wrapper in dex-reader's bundled zip implementation. When the underlying inflater stream (super.read) throws an IOException while decompressing a zip entry, it is re-wrapped as 'Error reading data for <entryName> near offset <bytesRead>', preserving the entry name and bytes read so far plus the original cause.

Solutions

  1. Verify archive integrity (zip -t / unzip -t) and re-obtain the file; the deflate stream is corrupt at that offset.
  2. Inspect IOException.getCause() to distinguish zip format corruption from file I/O errors.
  3. When processing untrusted archives, catch this IOException per entry and skip the bad entry instead of aborting the whole file.
  4. Ensure the ZipFile's backing file is not truncated or closed while being read.

Example fix

// before
try (InputStream in = zipFile.getInputStream(entry)) {
    byte[] data = in.readAllBytes(); // throws on corrupt entry
}
// after
try (InputStream in = zipFile.getInputStream(entry)) {
    byte[] data = in.readAllBytes();
} catch (IOException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Error reading data for")) {
        logger.warn("Skipping corrupt zip entry", e);
    } else {
        throw e;
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check archive integrity before opening with ZipFile
Process p = new ProcessBuilder("unzip", "-t", archivePath).redirectErrorStream(true).start();
if (p.waitFor() != 0) throw new IllegalStateException("Archive corrupt: " + archivePath);

Type guard

// Java has no type guards; validate entry metadata before reading
static boolean isReadableEntry(ZipEntry e) {
    return e != null && !e.isDirectory() && e.getSize() >= 0;
}

Try / catch

try (InputStream in = zipFile.getInputStream(entry)) {
    in.transferTo(out);
} catch (IOException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Error reading data for")) {
        logger.warn("Corrupt zip entry skipped (offset info in message)", e);
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling ZipFile.getInputStream(entry).read(...) where the underlying stream read throws: corrupt or truncated deflate data, mismatched CRC/compression metadata, or an I/O fault reading the backing file mid-entry.

Common situations: Reading a corrupted, partially downloaded, or maliciously crafted .apk/.jar archive; archives modified after the central directory was written; disk/network faults while the archive is streamed.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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

Appendix: source

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

        }
    }

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

    private static class ByteBufferBackedInputStream extends InputStream {

View on GitHub (pinned to b5bda4fb49)