{"record":{"id":"92e9d0b3a954c25b","repo":"can1357/oh-my-pi","slug":"zip-member-path-name-is-too-long-to-write","errorCode":null,"errorMessage":"ZIP member path '${name}' is too long to write","messagePattern":"ZIP member path '(.+?)' is too long to write","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/zip.ts","lineNumber":631,"sourceCode":"\t\tconst centralParts: Uint8Array[] = [];\n\t\tlet localSize = 0;\n\t\tlet centralSize = 0;\n\t\tlet count = 0;\n\t\tfor (const [inputName, data] of members) {\n\t\t\tconst portableName = inputName.replace(/\\\\/g, \"/\");\n\t\t\tconst normalizedName = normalizeArchiveEntryPath(portableName);\n\t\t\tif (\n\t\t\t\t!normalizedName ||\n\t\t\t\tnormalizedName !== portableName.replace(/^\\.\\//, \"\") ||\n\t\t\t\tportableName.startsWith(\"/\") ||\n\t\t\t\t/^[A-Za-z]:/.test(portableName) ||\n\t\t\t\tportableName.includes(\"\\0\")\n\t\t\t) {\n\t\t\t\tthrow new ArchiveError(`Cannot write unsafe ZIP member path '${inputName}'`);\n\t\t\t}\n\t\t\tconst name = normalizedName;\n\t\t\tconst nameBytes = TEXT_ENCODER.encode(name);\n\t\t\tif (nameBytes.byteLength > U16_MAX) throw new ArchiveError(`ZIP member path '${name}' is too long to write`);\n\t\t\tif (data.byteLength >= U32_MAX) throw new ArchiveError(`ZIP member '${name}' is too large to write`);\n\t\t\tconst deflated = data.byteLength === 0 ? undefined : zlib.deflateRawSync(data);\n\t\t\tconst payload = deflated && deflated.byteLength < data.byteLength ? deflated : data;\n\t\t\tconst method = payload === data ? 0 : 8;\n\t\t\tif (payload.byteLength >= U32_MAX || localSize >= U32_MAX) {\n\t\t\t\tthrow new ArchiveError(\"ZIP archive is too large to write member offsets safely\");\n\t\t\t}\n\t\t\tconst checksum = crc32(data);\n\t\t\tconst local = new Uint8Array(30 + nameBytes.byteLength);\n\t\t\twriteUInt32LE(local, 0, LOCAL_HEADER_SIGNATURE);\n\t\t\twriteUInt16LE(local, 4, 20);\n\t\t\twriteUInt16LE(local, 6, UTF8_FLAG);\n\t\t\twriteUInt16LE(local, 8, method);\n\t\t\twriteUInt16LE(local, 10, 0);\n\t\t\twriteUInt16LE(local, 12, 0x21);\n\t\t\twriteUInt32LE(local, 14, checksum);\n\t\t\twriteUInt32LE(local, 18, payload.byteLength);\n\t\t\twriteUInt32LE(local, 22, data.byteLength);","sourceCodeStart":613,"sourceCodeEnd":649,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/zip.ts#L613-L649","documentation":"Thrown by the ZIP writer when the UTF-8 encoded member path exceeds U16_MAX (65535) bytes, the maximum the ZIP local/central header name-length fields can hold. The name simply cannot be represented in the ZIP format.","triggerScenarios":"Calling the zip write API with an absurdly long member name — typically from concatenating deep directory prefixes or from untrusted input containing a multi-kilobyte filename (each non-ASCII char costs up to 4 bytes).","commonSituations":"Generated names embedding long content (hashes, base64 blobs, URLs) into filenames; recursive directory trees near PATH_MAX with long segment chains; malicious uploads with oversized names.","solutions":["Shorten the member name before writing (truncate segments or hash long parts into a compact name)","Strip or flatten deep directory prefixes so the path fits within 65535 UTF-8 bytes","Validate name byte length (`Buffer.byteLength(name, 'utf8')`) before calling the writer and reject early"],"exampleFix":"// before\nwriteZip([{ name: `very/deep/prefix/${hugeGeneratedName}`, data }]);\n// after\nlet name = `very/deep/prefix/${hugeGeneratedName}`;\nif (Buffer.byteLength(name, 'utf8') > 65535) name = `very/deep/prefix/${hash(hugeGeneratedName)}`;\nwriteZip([{ name, data }]);","handlingStrategy":"validation","validationCode":"function assertZipNameFits(name: string): void {\n  if (Buffer.byteLength(name, 'utf8') > 65535)\n    throw new Error(`member name too long (${Buffer.byteLength(name, 'utf8')} bytes): ${name.slice(0, 50)}...`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await writeZip([{ name, data }]);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes('too long to write')) {\n    const short = `entry-${Bun.hash(name)}.bin`;\n    await writeZip([{ name: short, data }]);\n    return short;\n  }\n  throw err;\n}","preventionTips":["Cap generated filename length before writing","Hash long identifiers instead of embedding them in names","Remember UTF-8 encoding: non-ASCII names cost up to 4 bytes/char"],"tags":["zip","limits","validation","filename"],"backgroundTag":"zip-member-path-too-long","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}