pxb1988/dex2jar · error · ZipException

Spanned archives not supported

Error message

Spanned archives not supported

What it means

The EOCD record declares mismatched entry counts (numEntries vs totalNumEntries) or a non-zero disk number (diskNumber / diskWithCentralDir), indicating a multi-disk (spanned) archive, which this ZipFile does not support.

Solutions

  1. Re-merge the split archive into a single zip (zip -s 0 split.zip --out single.zip) before opening
  2. Rebuild/re-download the archive as a single volume
  3. If counts are merely inconsistent due to corruption, repair the zip with zip -FF

Example fix

null
Defensive patterns

Strategy: validation

Validate before calling

// detect split archives by sibling volume files
boolean isSplit = new File(base + ".z01").exists() || base.endsWith(".zip");

Type guard

null

Try / catch

try { ZipFile z = new ZipFile(f); } catch (ZipException e) { if (e.getMessage().contains("Spanned")) throw new IOException("merge split archive first"); throw e; }

Prevention

When it happens

Trigger: Opening a split/multi-volume zip, or a zip whose EOCD entry counts are inconsistent/corrupted.

Common situations: Archives split by tools into .zip/.z01 volumes, partially copied multi-part archives, EOCD byte corruption.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

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

            if (scanOffset < stopOffset) {
                throw new ZipException("End Of Central Directory signature not found");
            }
        }

        // Read the End Of Central Directory. ENDHDR includes the signature bytes,
        // which we've already read.

        // Pull out the information we need.
        int diskNumber = raf.getShort() & 0xffff;
        int diskWithCentralDir = raf.getShort() & 0xffff;
        int numEntries = raf.getShort() & 0xffff;
        int totalNumEntries = raf.getShort() & 0xffff;
        skip(raf, 4); // Ignore centralDirSize.
        long centralDirOffset = ((long) raf.getInt()) & 0xffffffffL;
        int commentLength = raf.getShort() & 0xffff;

        if (numEntries != totalNumEntries || diskNumber != 0 || diskWithCentralDir != 0) {
            throw new ZipException("Spanned archives not supported");
        }
        boolean skipCommentsAndExtra = true;

        if (commentLength > 0) {
            if (commentLength > raf.remaining()) {
                System.err.println("WARN: the zip comment exceed the zip content");
            } else {
                if (skipCommentsAndExtra) {
                    skip(raf, commentLength);
                } else {
                    byte[] commentBytes = new byte[commentLength];
                    raf.get(commentBytes);
                    comment = new String(commentBytes, 0, commentBytes.length, StandardCharsets.UTF_8);
                }
            }
        }

        // Seek to the first CDE and read all entries.

View on GitHub (pinned to b5bda4fb49)