{"record":{"id":"a105af9cdf4cbfa3","repo":"can1357/oh-my-pi","slug":"zip-archive-is-too-large-to-write","errorCode":null,"errorMessage":"ZIP archive is too large to write","messagePattern":"ZIP archive is too large to write","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/zip.ts","lineNumber":674,"sourceCode":"\t\t\twriteUInt16LE(central, 4, (UNIX_HOST << 8) | 20);\n\t\t\twriteUInt16LE(central, 6, 20);\n\t\t\twriteUInt16LE(central, 8, UTF8_FLAG);\n\t\t\twriteUInt16LE(central, 10, method);\n\t\t\twriteUInt16LE(central, 12, 0);\n\t\t\twriteUInt16LE(central, 14, 0x21);\n\t\t\twriteUInt32LE(central, 16, checksum);\n\t\t\twriteUInt32LE(central, 20, payload.byteLength);\n\t\t\twriteUInt32LE(central, 24, data.byteLength);\n\t\t\twriteUInt16LE(central, 28, nameBytes.byteLength);\n\t\t\twriteUInt32LE(central, 38, (0o100644 << 16) >>> 0);\n\t\t\twriteUInt32LE(central, 42, localSize);\n\t\t\tcentral.set(nameBytes, 46);\n\t\t\tcentralParts.push(central);\n\t\t\tlocalSize += local.byteLength + payload.byteLength;\n\t\t\tcentralSize += central.byteLength;\n\t\t\tcount++;\n\t\t\tif (!Number.isSafeInteger(localSize + centralSize) || count > U32_MAX) {\n\t\t\t\tthrow new ArchiveError(\"ZIP archive is too large to write\");\n\t\t\t}\n\t\t}\n\t\tif (localSize >= U32_MAX || centralSize >= U32_MAX) {\n\t\t\tthrow new ArchiveError(\"ZIP archive is too large to write member offsets safely\");\n\t\t}\n\t\tconst zip64 = count >= U16_MAX;\n\t\tconst trailerLength = EOCD_LENGTH + (zip64 ? ZIP64_EOCD_LENGTH + ZIP64_LOCATOR_LENGTH : 0);\n\t\tconst totalSize = localSize + centralSize + trailerLength;\n\t\tif (!Number.isSafeInteger(totalSize)) throw new ArchiveError(\"ZIP archive is too large to write\");\n\t\tconst output = new Uint8Array(totalSize);\n\t\tlet outputOffset = 0;\n\t\tfor (const part of localParts) {\n\t\t\toutput.set(part, outputOffset);\n\t\t\toutputOffset += part.byteLength;\n\t\t}\n\t\tfor (const part of centralParts) {\n\t\t\toutput.set(part, outputOffset);\n\t\t\toutputOffset += part.byteLength;","sourceCodeStart":656,"sourceCodeEnd":692,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/zip.ts#L656-L692","documentation":"Final sanity check in the ZIP writer: the accumulated local-data size plus central-directory size must stay a safe integer, and the member count must not exceed U32_MAX. Exceeding these means the archive bookkeeping can no longer be represented correctly, so the writer aborts.","triggerScenarios":"Calling the zip write API with an enormous number of members (> 4,294,967,295 entries) or sizes whose running total overflows Number.isSafeInteger (>= 2^53 bytes) — practically, extremely large in-memory archive builds.","commonSituations":"Archiving millions of tiny files (e.g. node_modules, extracted datasets) into one zip in memory; runaway code adding members in a loop without a bound; accumulator bugs in generated member lists.","solutions":["Split the members across multiple ZIP archives (batch writes, e.g. 10k-100k members per archive)","Deduplicate or exclude generated files before archiving (respect ignore lists)","Check member count and total size before calling the writer and shard accordingly","Use a streaming archiver designed for very large entry counts"],"exampleFix":"// before: single zip of every file\nawait writeZip(millionsOfMembers);\n// after: batch\nfor (let i = 0; i < millionsOfMembers.length; i += 50000)\n  await writeZip(millionsOfMembers.slice(i, i + 50000).map((m, j) => ({ ...m, name: `part${i / 50000}/${m.name}` })));","handlingStrategy":"validation","validationCode":"function assertZipBookkeepingSafe(members: { name: string; data: Uint8Array }[]): void {\n  const count = members.length;\n  const total = members.reduce((s, m) => s + 30 + Buffer.byteLength(m.name, 'utf8') + m.data.byteLength, 0) + count * 46;\n  if (!Number.isSafeInteger(total) || count > 0xffffffff)\n    throw new Error(`zip too large: ${count} entries, ${total} bytes`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await writeZip(members);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message === 'ZIP archive is too large to write') {\n    logger.error('zip bookkeeping overflow', { entryCount: members.length });\n    return batchWriteZips(members, 50000);\n  }\n  throw err;\n}","preventionTips":["Cap member count per archive with batching","Exclude vendored/generated file floods via ignore lists","Sum member sizes before writing to catch overflow early"],"tags":["zip","limits","entry-count","size-limit"],"backgroundTag":"zip-entry-count-limit","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}