{"record":{"id":"825fd2a276a8874d","repo":"can1357/oh-my-pi","slug":"invalid-zip-archive-missing-zip64-central-directo","errorCode":null,"errorMessage":"Invalid ZIP archive: missing ZIP64 central-directory metadata","messagePattern":"Invalid ZIP archive: missing ZIP64 central-directory metadata","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/zip.ts","lineNumber":207,"sourceCode":"\tconst centralDisk = readUInt16LE(tail, eocdIndex + 6);\n\tconst entriesOnDisk = readUInt16LE(tail, eocdIndex + 8);\n\tlet entries = readUInt16LE(tail, eocdIndex + 10);\n\tlet size = readUInt32LE(tail, eocdIndex + 12);\n\tlet offset = readUInt32LE(tail, eocdIndex + 16);\n\tif (\n\t\tdisk !== 0 ||\n\t\tcentralDisk !== 0 ||\n\t\t(entriesOnDisk !== U16_MAX && entries !== U16_MAX && entriesOnDisk !== entries)\n\t) {\n\t\tthrow new ArchiveError(\"Multi-volume ZIP archives are not supported\");\n\t}\n\tconst needsZip64 = entriesOnDisk === U16_MAX || entries === U16_MAX || size === U32_MAX || offset === U32_MAX;\n\tconst zip64 = await readZip64Info(source, tail, tailStart, eocdOffset);\n\tlet physicalEnd = eocdOffset;\n\tif (zip64) {\n\t\t({ entries, size, offset, physicalEnd } = zip64);\n\t} else if (needsZip64) {\n\t\tthrow new ArchiveError(\"Invalid ZIP archive: missing ZIP64 central-directory metadata\");\n\t}\n\tassertEntryCount(entries, limits);\n\tassertIndexSize(size, limits, \"ZIP central directory\");\n\tif (entries > Math.floor(size / 46)) throw new ArchiveError(\"Invalid ZIP archive: truncated central directory\");\n\tconst declaredOffset = offset;\n\tconst info = { entries, size, offset, physicalEnd, archiveOffset: 0 };\n\tinfo.offset = await locateCentralDirectory(source, info);\n\tinfo.archiveOffset = info.offset - declaredOffset;\n\tcheckedEnd(info.offset, info.size, source.size, \"central directory\");\n\treturn info;\n}\n\nfunction filetimeToMs(bytes: Uint8Array, offset: number): number | undefined {\n\tlet value = 0n;\n\tfor (let index = 7; index >= 0; index--) value = (value << 8n) | BigInt(bytes[offset + index]!);\n\tconst milliseconds = value / 10_000n - WINDOWS_EPOCH_FILETIME_MS;\n\tconst number = Number(milliseconds);\n\treturn Number.isSafeInteger(number) ? number : undefined;","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/zip.ts#L189-L225","documentation":"Thrown by readCentralDirectoryInfo when the EOCD uses ZIP64 sentinel values (0xFFFF entry counts or 0xFFFFFFFF size/offset) — meaning real values live in ZIP64 locator/EOCD records — but no valid ZIP64 EOCD could be found or validated by readZip64Info. The archive claims ZIP64 metadata that does not exist.","triggerScenarios":"Calling zip info/read on an archive whose EOCD fields are the ZIP64 sentinels while the 20-byte ZIP64 locator and 56-byte ZIP64 EOCD are absent, corrupted, or whose declared offsets don't line up (extensible-data size mismatch, wrong totalRecords).","commonSituations":"Archives larger than 4 GB or with 65535+ entries whose writer set ZIP64 markers but failed to emit the ZIP64 EOCD; third-party writers with incomplete ZIP64 support; corruption of the final bytes of a large archive.","solutions":["Verify with `unzip -t` or `zipinfo -v`; if standard tools also fail, the archive is malformed.","Recreate the archive with a mature writer (Info-ZIP, 7-Zip, Python zipfile) and force ZIP64 where needed.","Repair with `zip -FF broken.zip --out fixed.zip` and retry.","If a custom writer emitted sentinel values, fix it to always write the ZIP64 locator + EOCD when using sentinels."],"exampleFix":"// before: reading an archive from a homegrown writer that sets ZIP64 sentinels\nconst zip = readZip(customWriterOutput);\n// after: validate with a reference tool first, or re-zip\nawait $`7z t ${customWriterOutput}`.nothrow();\nawait $`zip -r rebuilt.zip ./data`; // standard writer emits proper ZIP64 EOCD\nconst zip = readZip(\"rebuilt.zip\");","handlingStrategy":"validation","validationCode":"// Pre-flight with a battle-tested parser before using this library on large archives.\nimport * as fs from \"node:fs/promises\";\nconst size = (await fs.stat(path)).size;\nif (size > 4 * 1024 * 1024 * 1024) {\n  // must be ZIP64; require the caller to have validated it (e.g. `unzip -t` passed)\n  if (!preValidated) throw new Error(\"oversized zip must be validated as ZIP64 before reading\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  const zip = readZip(largeArchivePath);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes(\"missing ZIP64 central-directory metadata\")) {\n    // archive declares ZIP64 but the records are absent/corrupt: repair or re-zip\n    await $`zip -FF ${path} --out ${path}.fixed.zip`.nothrow();\n    return readZip(`${path}.fixed.zip`);\n  }\n  throw err;\n}","preventionTips":["Create >4GB or >65535-entry archives only with mature writers (Info-ZIP, 7-Zip, Python zipfile).","Validate large archives with `unzip -t` right after production/transfer.","If writing zips yourself, always emit the ZIP64 locator + EOCD whenever you use sentinel values.","Keep checksums for large archives to distinguish corruption from format bugs."],"tags":["zip","archive","zip64","corruption"],"backgroundTag":"zip64-metadata-missing","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}