can1357/oh-my-pi · error · ArchiveError
Invalid ZIP archive: size mismatch for '${memberPath}' (expe
Error message
Invalid ZIP archive: size mismatch for '${memberPath}' (expected ${size}, got ${this.#compressedSize}) What it means
Thrown for stored (method 0) members whose central-directory uncompressed size differs from the compressed size. Stored data must be byte-identical to the original, so both size fields must match; a mismatch means the header metadata is wrong or the data was altered. ArchiveError including expected vs actual sizes.
Source
Thrown at packages/utils/src/ar/zip.ts:420
`local header for '${memberPath}'`,
);
const header = await this.#source.read(this.#localHeaderOffset, headerEnd);
if (header.byteLength !== 30 || readUInt32LE(header, 0) !== LOCAL_HEADER_SIGNATURE) {
throw new ArchiveError(`Invalid ZIP archive: malformed local header for '${memberPath}'`);
}
const localFlags = readUInt16LE(header, 6);
if ((localFlags & (ENCRYPTED_FLAG | STRONG_ENCRYPTION_FLAG)) !== 0) {
throw new ArchiveError(`Encrypted ZIP member '${memberPath}' is not supported`);
}
if (readUInt16LE(header, 8) !== this.#method) {
throw new ArchiveError(
`Invalid ZIP archive: local and central compression methods disagree for '${memberPath}'`,
);
}
const dataStart = this.#localHeaderOffset + 30 + readUInt16LE(header, 26) + readUInt16LE(header, 28);
const dataEnd = checkedEnd(dataStart, this.#compressedSize, this.#source.size, `data for '${memberPath}'`);
if (this.#method === 0 && this.#compressedSize !== size) {
throw new ArchiveError(
`Invalid ZIP archive: size mismatch for '${memberPath}' (expected ${size}, got ${this.#compressedSize})`,
);
}
const compressed = await this.#source.read(dataStart, dataEnd);
if (compressed.byteLength !== this.#compressedSize) {
throw new ArchiveError(`Invalid ZIP archive: truncated data for '${memberPath}'`);
}
const decoded = await decodeMember(compressed, this.#method, size, memberPath);
if (decoded.byteLength !== size) {
throw new ArchiveError(
`Invalid ZIP archive: size mismatch for '${memberPath}' (expected ${size}, got ${decoded.byteLength})`,
);
}
const actualCrc = crc32(decoded);
if (actualCrc !== this.#crc) {
throw new ArchiveError(`Invalid ZIP archive: CRC mismatch for '${memberPath}'`);
}
return decoded;View on GitHub (pinned to 9690622007)
Solutions
- Validate with `unzip -t` and re-obtain a clean copy of the archive
- Re-zip the source files to regenerate correct size fields
- If you wrote the archive, fix the writer to update both compressed and uncompressed sizes for stored entries
- For streamed writing, use data descriptors correctly or seek back to patch the local header
Example fix
// before: writer stores size only in central directory
await readZipMember(zip, 'blob.raw'); // throws 3714
// after: re-create with consistent headers
// $ `zip -0 -r fixed.zip dir/`
await readZipMember(await readZip(Bun.file('fixed.zip')), 'blob.raw'); Defensive patterns
Strategy: validation
Validate before calling
// For stored entries, compressed and uncompressed sizes must match
if (entry.method === 0 && entry.compressedSize !== entry.size) {
throw new Error('stored entry has inconsistent sizes — regenerate archive');
} Try / catch
try {
const data = await zip.read(member);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes('size mismatch')) {
throw new Error('ZIP metadata inconsistent for stored member; re-zip the source data');
}
throw err;
} Prevention
- Use data descriptors correctly when streaming zips, or seek back and patch sizes
- Write both size fields consistently in any custom zip writer
- Verify archives from untrusted writers with `unzip -t` before ingestion
- Prefer deflate over stored when sizes are computed automatically
When it happens
Trigger: Reading a method-0 member where #compressedSize !== size — e.g. sizes patched inconsistently in the two header sets, or data appended/replaced without updating both size fields; note data-descriptor (streamed) zips that store 0 sizes legitimately take a different path per spec, but corrupted ones hit this check.
Common situations: Zips produced by broken streaming writers that mis-report stored sizes; files whose data was edited in place; archives damaged in transit; maliciously crafted zips.
Related errors
- Invalid ZIP archive: size mismatch for '${memberPath}' (expe
- Invalid ZIP archive: ${what} has an invalid range
- Invalid ZIP archive: missing end of central directory
- Invalid ZIP archive: missing ZIP64 end of central directory
- Invalid ZIP archive: malformed local header for '${memberPat
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/4e49bfae3f6d8c59.
Report an issue: GitHub.