Tencent/tinker · error · ZipException
Spanned archives not supported
Error message
Spanned archives not supported
What it means
While parsing the End Of Central Directory record (non-zip64 path), TinkerZipFile checks that the entry count on this disk equals the total entry count and that both disk-number fields are zero. Any mismatch means the archive is split across multiple disks/volumes, which this reader does not support, so it throws ZipException('Spanned archives not supported'). This is the same restriction as java.util.zip.ZipFile.
Source
Thrown at third-party/tinker-ziputils/src/main/java/com/tencent/tinker/ziputils/ziputil/TinkerZipFile.java:224
if (isZip64) {
numEntries = -1;
centralDirOffset = -1;
// If we have a zip64 end of central directory record, we skip through the regular
// end of central directory record and use the information from the zip64 eocd record.
// We're still forced to read the comment length (below) since it isn't present in the
// zip64 eocd record.
it.skip(16);
} else {
// If we don't have a zip64 eocd record, we read values from the "regular"
// eocd record.
int diskNumber = it.readShort() & 0xffff;
int diskWithCentralDir = it.readShort() & 0xffff;
numEntries = it.readShort() & 0xffff;
int totalNumEntries = it.readShort() & 0xffff;
it.skip(4); // Ignore centralDirSize.
centralDirOffset = ((long) it.readInt()) & 0xffffffffL;
if (numEntries != totalNumEntries || diskNumber != 0 || diskWithCentralDir != 0) {
throw new ZipException("Spanned archives not supported");
}
}
final int commentLength = it.readShort() & 0xffff;
return new EocdRecord(numEntries, centralDirOffset, commentLength);
}
static void throwZipException(String filename, long fileSize, String entryName, long localHeaderRelOffset, String msg, int magic) throws ZipException {
final String hexString = Integer.toHexString(magic);
throw new ZipException("file name:" + filename
+ ", file size" + fileSize
+ ", entry name:" + entryName
+ ", entry localHeaderRelOffset:" + localHeaderRelOffset
+ ", "
+ msg + " signature not found; was " + hexString);
}
/**
* Closes this zip file. This method is idempotent. This method may cause I/O if theView on GitHub (pinned to 1b7ea02c23)
Solutions
- Rejoin all parts into a single file before opening (e.g. 'zip -s 0 archive.zip --out full.zip' or 'zip -F').
- If the file should be single-part, treat this as corruption: re-download or regenerate the archive.
- Verify with 'unzip -l' or 'zipinfo' that the archive is a self-contained single-volume zip before handing it to TinkerZipFile.
Example fix
// before
TinkerZipFile zf = new TinkerZipFile(new File("patch-part1.zip")); // spanned archive
// after
// merge parts first: zip -s 0 patch.zip --out patch-full.zip
TinkerZipFile zf = new TinkerZipFile(new File("patch-full.zip")); Defensive patterns
Strategy: validation
Validate before calling
// cheap pre-check: EOCD disk fields must be zero for a single-volume zip
static boolean isSingleVolume(File f) throws IOException {
try (RandomAccessFile r = new RandomAccessFile(f, "r")) {
long len = r.length();
if (len < 22) return false;
for (long off = len - 22; off >= Math.max(0, len - 22 - 65536); off--) {
r.seek(off);
if (r.readInt() == 0x06054b50) { // ENDSIG little-endian after reverseBytes
r.seek(off + 4);
return (r.readShort() | r.readShort()) == 0; // diskNumber & diskWithCentralDir
}
}
}
return false;
} Try / catch
try {
zf = new TinkerZipFile(file);
} catch (ZipException e) {
if (e.getMessage().contains("Spanned archives")) {
// actionable: merge parts, then reopen
throw new IllegalArgumentException("Multi-part archive not supported: merge parts first", e);
}
throw e;
} Prevention
- Reject multi-part archives at upload/ingestion with a dedicated check and message.
- Standardize on single-volume zips in your distribution pipeline.
- Validate with 'zipinfo' in CI for any archive you feed to TinkerZipFile.
When it happens
Trigger: Opening a multi-part zip (created with 'zip -s', WinRAR split, or hjsplit) with new TinkerZipFile(...): the EOCD then reports diskNumber != 0, diskWithCentralDir != 0, or per-disk numEntries != totalNumEntries.
Common situations: Android patch/OTA files distributed as split archives; a download tool that stored parts without rejoining; a truncated single-disk archive whose EOCD fields were corrupted so they resemble a spanned set.
Related errors
- Expected ${DEX_IN_JAR_NAME} in ${file}
- CRC mismatch
- Size mismatch
- Entry already exists: {}
- Too many entries for the zip file format's 16-bit entry coun
AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14).
Data as JSON: /api/errors/5a8ffaf4d34eb8c4.
Report an issue: GitHub.