{"record":{"id":"f0e87dc37ded73ae","repo":"can1357/oh-my-pi","slug":"archive-is-too-large-to-read-safely-f0e87d","errorCode":null,"errorMessage":"Archive is too large to read safely","messagePattern":"Archive is too large to read safely","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/rar.ts","lineNumber":152,"sourceCode":"\t\t\t}\n\t\t\tif (output.byteLength !== record.unpackedSize) corrupt(`member '${record.path}' size mismatch`);\n\t\t\tif (record.crc !== undefined && crc32(output) !== record.crc) {\n\t\t\t\tthrow new ArchiveError(`RAR member '${record.path}' CRC32 mismatch`);\n\t\t\t}\n\t\t\tthis.#cache.set(current, output.slice());\n\t\t}\n\t}\n}\n\n/** Probe the RAR 1.5-4.x or RAR5 signature. */\nexport function sniffRar(bytes: Uint8Array): boolean {\n\treturn findMarker(bytes) !== undefined;\n}\n\n/** Index a RAR4 or RAR5 archive and defer member decompression until extraction. */\nexport const readRar: FormatReader = async (source, options) => {\n\tif (!Number.isSafeInteger(source.size) || source.size < 0) {\n\t\tthrow new ArchiveError(\"Archive is too large to read safely\");\n\t}\n\tconst indexed = await indexRarMetadata(source, options);\n\tconst bytes = sparseBytes(source.size, indexed.segments);\n\tconst marker = indexed.marker;\n\tconst records =\n\t\tmarker.version === 5 ? parseRar5(bytes, marker.offset, options) : parseRar4(bytes, marker.offset, options);\n\tconst archive = new RarArchive(source, records, options);\n\tconst entries: ArchiveIndexEntry[] = [];\n\tfor (let index = 0; index < records.length; index++) {\n\t\tconst record = records[index]!;\n\t\tconst entry: ArchiveIndexEntry = {\n\t\t\tpath: record.path,\n\t\t\tisDirectory: record.isDirectory,\n\t\t\tsize: record.unpackedSize,\n\t\t};\n\t\tif (record.mtimeMs !== undefined) entry.mtimeMs = record.mtimeMs;\n\t\tif (record.mode !== undefined) entry.mode = record.mode;\n\t\tif (record.linkTarget !== undefined) {","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/rar.ts#L134-L170","documentation":"readRar() validates source.size before doing any work: it must be a non-negative safe integer. Otherwise the sparse-read strategy (which allocates based on size) would be unsafe, so it throws 'Archive is too large to read safely'.","triggerScenarios":"Calling readRar(source, options) where source.size is undefined, negative, fractional, or exceeds Number.MAX_SAFE_INTEGER — e.g. a Blob/File with unknown size, a streaming source reporting -1, or a bogus stat.","commonSituations":"Passing a handle to a pipe/device whose size is unknown; using a custom Source implementation that doesn't populate size; 32-bit overflow artifacts in metadata.","solutions":["Ensure the Source has an accurate numeric size before calling readRar (stat the file and populate source.size)","If the source is a stream of unknown length, buffer it to a file first and index from that","Sanitize the size you report (0 <= size <= MAX_SAFE_INTEGER)"],"exampleFix":"// before\nawait readRar({ size: file.size ?? -1, read }, options);\n// after\nconst stat = await fs.stat(path);\nawait readRar({ size: stat.size, read }, options);","handlingStrategy":"validation","validationCode":"if (!Number.isSafeInteger(source.size) || source.size < 0) {\n  throw new Error('Source size must be a non-negative safe integer before calling readRar');\n}","typeGuard":"function hasValidSize(source: { size: unknown }): source is { size: number } {\n  return typeof source.size === 'number' && Number.isSafeInteger(source.size) && source.size >= 0;\n}","tryCatchPattern":"try {\n  const reader = await readRar(source, options);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message === 'Archive is too large to read safely') {\n    throw new Error('Provide a source with a known, non-negative integer size');\n  }\n  throw err;\n}","preventionTips":["Stat files and populate source.size explicitly; never pass undefined/-1 placeholders","For streams of unknown length, spill to a temp file and index from the file","Coerce sizes from 32-bit APIs carefully (negative overflow) before constructing the Source"],"tags":["rar","archive","size-validation","input-validation"],"backgroundTag":"invalid-input-size","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}