{"record":{"id":"52ea30aff9e39419","repo":"can1357/oh-my-pi","slug":"invalid-zip-archive-what-has-an-invalid-range","errorCode":null,"errorMessage":"Invalid ZIP archive: ${what} has an invalid range","messagePattern":"Invalid ZIP archive: (.+?) has an invalid range","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/zip.ts","lineNumber":103,"sourceCode":"interface ParsedExtra {\n\tzip64?: Uint8Array;\n\tunicodePath?: string;\n\tmtimeMs?: number;\n}\n\ninterface ParsedZipEntry {\n\tentry: ArchiveIndexEntry;\n\tisSymlink: boolean;\n}\n\nfunction archiveError(error: unknown, context: string): ArchiveError {\n\tif (error instanceof ArchiveError) return error;\n\treturn new ArchiveError(`${context}: ${error instanceof Error ? error.message : String(error)}`);\n}\n\nfunction checkedEnd(start: number, size: number, archiveSize: number, what: string): number {\n\tif (!Number.isSafeInteger(start) || !Number.isSafeInteger(size) || start < 0 || size < 0) {\n\t\tthrow new ArchiveError(`Invalid ZIP archive: ${what} has an invalid range`);\n\t}\n\tconst end = start + size;\n\tif (!Number.isSafeInteger(end) || end > archiveSize) {\n\t\tthrow new ArchiveError(`Invalid ZIP archive: ${what} exceeds archive size`);\n\t}\n\treturn end;\n}\n\nfunction findEocd(tail: Uint8Array): number {\n\tfor (let offset = tail.byteLength - EOCD_LENGTH; offset >= 0; offset--) {\n\t\tif (readUInt32LE(tail, offset) !== EOCD_SIGNATURE) continue;\n\t\tif (offset + EOCD_LENGTH + readUInt16LE(tail, offset + 20) === tail.byteLength) return offset;\n\t}\n\tthrow new ArchiveError(\"Invalid ZIP archive: missing end of central directory\");\n}\n\nasync function readZip64Info(\n\tsource: ByteSource,","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/zip.ts#L85-L121","documentation":"checkedEnd in zip.ts validates that a start/size pair describes a sane in-range span before any ZIP structure (local header, data, central directory entry) is used. This branch fires when either value is negative, non-finite, or not a safe integer — i.e. the ZIP metadata is nonsensical, not merely too large.","triggerScenarios":"readZip or its helpers computing a header/data/central-directory span where a parsed 32/64-bit field decodes to a negative or unsafe-integer value (e.g. a corrupted size or offset field, or a bad ZIP64 extra field).","commonSituations":"Corrupted ZIPs from interrupted downloads; ZIP files with flipped bits in central-directory fields; hand-modified archives; fuzzed or malicious inputs.","solutions":["Test the archive with `unzip -t` to confirm corruption, then re-obtain it","If parsing untrusted input, treat this as an expected failure and reject the file up front","Check any code that pre-processes or patches ZIP fields for integer overflow or wrong endianness"],"exampleFix":"// before\nawait readZip(untrustedBytes);\n// after\nif (!looksLikeZip(untrustedBytes)) throw new Error(\"not a zip\");\ntry {\n  await readZip(untrustedBytes);\n} catch (e) {\n  if (e instanceof ArchiveError) return rejectUpload(\"corrupt zip: \" + e.message);\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"if (!Number.isSafeInteger(bytes.length) || bytes.length < 22) throw new Error(\"not a plausible zip\");\n// check EOCD signature exists in tail\nconst dec = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\nlet eocd = -1;\nfor (let i = bytes.length - 22; i >= Math.max(0, bytes.length - 22 - 65535); i--) {\n  if (dec.getUint32(i, true) === 0x06054b50) { eocd = i; break; }\n}\nif (eocd < 0) throw new Error(\"zip EOCD missing — refusing to parse\");","typeGuard":null,"tryCatchPattern":"try {\n  const zip = await readZip(bytes);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes(\"invalid range\")) {\n    return quarantine(err, \"zip metadata nonsensical — likely corrupt or hostile input\");\n  }\n  throw err;\n}","preventionTips":["Validate ZIP origin: check checksums/size before parsing untrusted files","Never accept archives from untrusted sources without size/structure validation","Keep the reader's errors (ArchiveError) mapped to a user-facing 'corrupt file' path"],"tags":["zip","archive","corrupt-archive","validation"],"backgroundTag":"zip-central-directory-corrupt","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}