{"record":{"id":"92102391b54aab7f","repo":"can1357/oh-my-pi","slug":"invalid-zip-archive-local-and-central-compression","errorCode":null,"errorMessage":"Invalid ZIP archive: local and central compression methods disagree for '${memberPath}'","messagePattern":"Invalid ZIP archive: local and central compression methods disagree for '(.+?)'","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/zip.ts","lineNumber":413,"sourceCode":"\t\t\tif (SUPPORTED_METHODS[this.#method] !== true) {\n\t\t\t\tthrow new ArchiveError(`Unsupported ZIP compression method ${this.#method} for '${memberPath}'`);\n\t\t\t}\n\t\t\tconst headerEnd = checkedEnd(\n\t\t\t\tthis.#localHeaderOffset,\n\t\t\t\t30,\n\t\t\t\tthis.#source.size,\n\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})`,","sourceCodeStart":395,"sourceCodeEnd":431,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/zip.ts#L395-L431","documentation":"Thrown when the compression method recorded in the member's local file header (offset 8) differs from the method in its central directory entry. A well-formed ZIP must have identical methods in both headers; disagreement means the archive was corrupted or hand-modified, so the library refuses to decode with either guess. ArchiveError naming the member.","triggerScenarios":"ZipMemberSource read where central directory says method X but the local header at localHeaderOffset says method Y — typically after byte-level patching, corrupting writes, or maliciously crafted archives.","commonSituations":"Archives repaired by naive tools that rewrite one header but not the other; files edited in hex or by scripts patching sizes/methods; deliberately malformed zips (fuzzing/security research); media with bit-rot.","solutions":["Verify the archive (`unzip -t`); if it fails, the file is corrupt — re-obtain it","Re-create the archive from the original source files rather than repairing","If repairing is required, use `zip -FF` which keeps headers consistent","If the archive comes from your own writer, fix the writer to emit matching local/central methods"],"exampleFix":"// before: reading a hex-edited zip\nawait readZipMember(zip, 'data.bin'); // throws 3713\n// after: repair then read\n// $ `zip -FF broken.zip --out fixed.zip`\nawait readZipMember(await readZip(Bun.file('fixed.zip')), 'data.bin');","handlingStrategy":"validation","validationCode":"// Cross-check local vs central method before reading\nif (localHeaderMethod(entry) !== entry.method) throw new Error('zip headers inconsistent — archive is corrupt');","typeGuard":null,"tryCatchPattern":"try {\n  const data = await zip.read(member);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes('methods disagree')) {\n    // attempt structural repair once: await $`zip -FF broken.zip --out fixed.zip`\n  } else throw err;\n}","preventionTips":["Never hand-edit ZIP bytes; re-create archives instead","Use reputable writers (Info-ZIP, 7-Zip, zip command) that keep headers in sync","Integrity-check (`unzip -t`) any archive that crossed an untrusted channel","If repairs are routine, fix the producing writer, not the consumer"],"tags":["zip","corrupt-archive","header-inconsistency","archive-parsing"],"backgroundTag":"corrupt-zip-archive","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}