{"record":{"id":"4e49bfae3f6d8c59","repo":"can1357/oh-my-pi","slug":"invalid-zip-archive-size-mismatch-for-memberpa","errorCode":null,"errorMessage":"Invalid ZIP archive: size mismatch for '${memberPath}' (expected ${size}, got ${this.#compressedSize})","messagePattern":"Invalid ZIP archive: size mismatch for '(.+?)' \\(expected (.+?), got (.+?)\\)","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/zip.ts","lineNumber":420,"sourceCode":"\t\t\t\t`local header for '${memberPath}'`,\n\t\t\t);\n\t\t\tconst header = await this.#source.read(this.#localHeaderOffset, headerEnd);\n\t\t\tif (header.byteLength !== 30 || readUInt32LE(header, 0) !== LOCAL_HEADER_SIGNATURE) {\n\t\t\t\tthrow new ArchiveError(`Invalid ZIP archive: malformed local header for '${memberPath}'`);\n\t\t\t}\n\t\t\tconst localFlags = readUInt16LE(header, 6);\n\t\t\tif ((localFlags & (ENCRYPTED_FLAG | STRONG_ENCRYPTION_FLAG)) !== 0) {\n\t\t\t\tthrow new ArchiveError(`Encrypted ZIP member '${memberPath}' is not supported`);\n\t\t\t}\n\t\t\tif (readUInt16LE(header, 8) !== this.#method) {\n\t\t\t\tthrow new ArchiveError(\n\t\t\t\t\t`Invalid ZIP archive: local and central compression methods disagree for '${memberPath}'`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst dataStart = this.#localHeaderOffset + 30 + readUInt16LE(header, 26) + readUInt16LE(header, 28);\n\t\t\tconst dataEnd = checkedEnd(dataStart, this.#compressedSize, this.#source.size, `data for '${memberPath}'`);\n\t\t\tif (this.#method === 0 && this.#compressedSize !== size) {\n\t\t\t\tthrow new ArchiveError(\n\t\t\t\t\t`Invalid ZIP archive: size mismatch for '${memberPath}' (expected ${size}, got ${this.#compressedSize})`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst compressed = await this.#source.read(dataStart, dataEnd);\n\t\t\tif (compressed.byteLength !== this.#compressedSize) {\n\t\t\t\tthrow new ArchiveError(`Invalid ZIP archive: truncated data for '${memberPath}'`);\n\t\t\t}\n\t\t\tconst decoded = await decodeMember(compressed, this.#method, size, memberPath);\n\t\t\tif (decoded.byteLength !== size) {\n\t\t\t\tthrow new ArchiveError(\n\t\t\t\t\t`Invalid ZIP archive: size mismatch for '${memberPath}' (expected ${size}, got ${decoded.byteLength})`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst actualCrc = crc32(decoded);\n\t\t\tif (actualCrc !== this.#crc) {\n\t\t\t\tthrow new ArchiveError(`Invalid ZIP archive: CRC mismatch for '${memberPath}'`);\n\t\t\t}\n\t\t\treturn decoded;","sourceCodeStart":402,"sourceCodeEnd":438,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/zip.ts#L402-L438","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: writer stores size only in central directory\nawait readZipMember(zip, 'blob.raw'); // throws 3714\n// after: re-create with consistent headers\n// $ `zip -0 -r fixed.zip dir/`\nawait readZipMember(await readZip(Bun.file('fixed.zip')), 'blob.raw');","handlingStrategy":"validation","validationCode":"// For stored entries, compressed and uncompressed sizes must match\nif (entry.method === 0 && entry.compressedSize !== entry.size) {\n  throw new Error('stored entry has inconsistent sizes — regenerate archive');\n}","typeGuard":null,"tryCatchPattern":"try {\n  const data = await zip.read(member);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes('size mismatch')) {\n    throw new Error('ZIP metadata inconsistent for stored member; re-zip the source data');\n  }\n  throw err;\n}","preventionTips":["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"],"tags":["zip","size-mismatch","corrupt-archive","stored-entry"],"backgroundTag":"zip-size-mismatch","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}