{"record":{"id":"00e52e1e2260d1c4","repo":"can1357/oh-my-pi","slug":"unsupported-multi-volume-rar5-archive","errorCode":null,"errorMessage":"Unsupported multi-volume RAR5 archive","messagePattern":"Unsupported multi-volume RAR5 archive","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/rar.ts","lineNumber":326,"sourceCode":"\tlet offset = marker + RAR5_MARKER.byteLength;\n\tlet sawMain = false;\n\twhile (offset < bytes.byteLength) {\n\t\tif (offset + 5 > bytes.byteLength) corrupt(\"truncated RAR5 header\");\n\t\tconst expectedHeaderCrc = readUInt32LE(bytes, offset);\n\t\tconst sizeAt = offset + 4;\n\t\tconst sizeCursor = { offset: sizeAt };\n\t\tconst headerSize = readVint(bytes, sizeCursor, bytes.byteLength, \"header size\");\n\t\tif (headerSize > 2 * 1024 * 1024) corrupt(\"RAR5 header exceeds format limit\");\n\t\tassertIndexSize(headerSize, options.limits, \"RAR5 header\");\n\t\tconst headerStart = sizeCursor.offset;\n\t\tconst headerEnd = checkedEnd(headerStart, headerSize, bytes.byteLength, \"RAR5 header\");\n\t\tif (crc32(bytes.subarray(sizeAt, headerEnd)) !== expectedHeaderCrc) corrupt(\"RAR5 header CRC32 mismatch\");\n\t\tconst cursor = { offset: headerStart };\n\t\tconst type = readVint(bytes, cursor, headerEnd, \"header type\");\n\t\tconst flags = readVint(bytes, cursor, headerEnd, \"header flags\");\n\t\tconst extraSize = (flags & 1) !== 0 ? readVint(bytes, cursor, headerEnd, \"extra area size\") : 0;\n\t\tconst dataSize = (flags & 2) !== 0 ? readVint(bytes, cursor, headerEnd, \"data size\") : 0;\n\t\tif ((flags & 0x18) !== 0) throw new ArchiveError(\"Unsupported multi-volume RAR5 archive\");\n\t\tconst dataStart = headerEnd;\n\t\tconst dataEnd = checkedEnd(dataStart, dataSize, bytes.byteLength, \"RAR5 data area\");\n\t\tif (extraSize > headerEnd - cursor.offset) corrupt(\"invalid RAR5 extra area size\");\n\t\tconst extraStart = headerEnd - extraSize;\n\n\t\tif (type === 4) throw new ArchiveError(\"Encrypted RAR5 headers are not supported\");\n\t\tif (type === 1) {\n\t\t\tconst archiveFlags = readVint(bytes, cursor, extraStart, \"archive flags\");\n\t\t\tif ((archiveFlags & 1) !== 0) throw new ArchiveError(\"Unsupported multi-volume RAR5 archive\");\n\t\t\tif ((archiveFlags & 8) !== 0) throw new ArchiveError(\"Unsupported RAR5 recovery record\");\n\t\t\tif ((archiveFlags & 2) !== 0) readVint(bytes, cursor, extraStart, \"volume number\");\n\t\t\tsawMain = true;\n\t\t} else if (type === 2 || type === 3) {\n\t\t\tconst fileFlags = readVint(bytes, cursor, extraStart, \"file flags\");\n\t\t\tconst unpackedSize = readVint(bytes, cursor, extraStart, \"unpacked size\");\n\t\t\tif ((fileFlags & 8) !== 0) throw new ArchiveError(\"RAR5 member with unknown unpacked size is not supported\");\n\t\t\tconst attributes = readVint(bytes, cursor, extraStart, \"file attributes\");\n\t\t\tlet mtimeMs: number | undefined;","sourceCodeStart":308,"sourceCodeEnd":344,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/rar.ts#L308-L344","documentation":"RAR5 headers carry per-header flags; bits 0x10 (split-before) and 0x08 (split-after) mark headers belonging to a file split across multiple archive volumes. This library parses single-file archives in memory only, so any header with these bits set is rejected with an ArchiveError.","triggerScenarios":"Calling the archive records/read API on a .part1.rar/.part2.rar multi-volume RAR5 set, or any RAR5 archive whose main/file header has the split-before (0x10) or split-after (0x08) flag set.","commonSituations":"Users created the archive with WinRAR's 'Split to volumes' option; a downloaded multipart archive where only the first part was passed to the parser; automated pipelines splitting large backups across volumes.","solutions":["Pass only a single-volume archive, or concatenate/rejoin the volume parts externally before parsing","Check the archive with WinRAR/7-Zip/unrar -v to confirm it is multipart","If you control archive creation, re-create without volume splitting"],"exampleFix":"// before\nconst records = readRar(fs.readFileSync('backup.part1.rar'));\n// after\n// rejoin volumes first, e.g. `cat backup.part*.rar > backup.rar`, then\nconst records = readRar(fs.readFileSync('backup.rar'));","handlingStrategy":"try-catch","validationCode":"const bytes = new Uint8Array(buf);\n// scan for a multi-volume marker is unreliable pre-parse; instead detect via file naming\nif (/\\.part\\d+\\.rar$/i.test(path)) throw new Error('multi-volume RAR not supported');","typeGuard":null,"tryCatchPattern":"try {\n  const records = readRar(bytes);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes('multi-volume')) {\n    // fall back to CLI extraction or surface 'multipart archive' to user\n  } else throw err;\n}","preventionTips":["Reject *.partN.rar filename patterns before parsing","Prefer single-volume archives when you control archive creation","Document that spanned volumes require external tools"],"tags":["rar5","archive","unsupported-feature","multipart"],"backgroundTag":"unsupported-archive-feature","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}