can1357/oh-my-pi · error · ArchiveError

Unsupported multi-volume RAR5 archive

Error message

Unsupported multi-volume RAR5 archive

What it means

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.

Source

Thrown at packages/utils/src/ar/rar.ts:326

	let offset = marker + RAR5_MARKER.byteLength;
	let sawMain = false;
	while (offset < bytes.byteLength) {
		if (offset + 5 > bytes.byteLength) corrupt("truncated RAR5 header");
		const expectedHeaderCrc = readUInt32LE(bytes, offset);
		const sizeAt = offset + 4;
		const sizeCursor = { offset: sizeAt };
		const headerSize = readVint(bytes, sizeCursor, bytes.byteLength, "header size");
		if (headerSize > 2 * 1024 * 1024) corrupt("RAR5 header exceeds format limit");
		assertIndexSize(headerSize, options.limits, "RAR5 header");
		const headerStart = sizeCursor.offset;
		const headerEnd = checkedEnd(headerStart, headerSize, bytes.byteLength, "RAR5 header");
		if (crc32(bytes.subarray(sizeAt, headerEnd)) !== expectedHeaderCrc) corrupt("RAR5 header CRC32 mismatch");
		const cursor = { offset: headerStart };
		const type = readVint(bytes, cursor, headerEnd, "header type");
		const flags = readVint(bytes, cursor, headerEnd, "header flags");
		const extraSize = (flags & 1) !== 0 ? readVint(bytes, cursor, headerEnd, "extra area size") : 0;
		const dataSize = (flags & 2) !== 0 ? readVint(bytes, cursor, headerEnd, "data size") : 0;
		if ((flags & 0x18) !== 0) throw new ArchiveError("Unsupported multi-volume RAR5 archive");
		const dataStart = headerEnd;
		const dataEnd = checkedEnd(dataStart, dataSize, bytes.byteLength, "RAR5 data area");
		if (extraSize > headerEnd - cursor.offset) corrupt("invalid RAR5 extra area size");
		const extraStart = headerEnd - extraSize;

		if (type === 4) throw new ArchiveError("Encrypted RAR5 headers are not supported");
		if (type === 1) {
			const archiveFlags = readVint(bytes, cursor, extraStart, "archive flags");
			if ((archiveFlags & 1) !== 0) throw new ArchiveError("Unsupported multi-volume RAR5 archive");
			if ((archiveFlags & 8) !== 0) throw new ArchiveError("Unsupported RAR5 recovery record");
			if ((archiveFlags & 2) !== 0) readVint(bytes, cursor, extraStart, "volume number");
			sawMain = true;
		} else if (type === 2 || type === 3) {
			const fileFlags = readVint(bytes, cursor, extraStart, "file flags");
			const unpackedSize = readVint(bytes, cursor, extraStart, "unpacked size");
			if ((fileFlags & 8) !== 0) throw new ArchiveError("RAR5 member with unknown unpacked size is not supported");
			const attributes = readVint(bytes, cursor, extraStart, "file attributes");
			let mtimeMs: number | undefined;

View on GitHub (pinned to 9690622007)

Solutions

  1. Pass only a single-volume archive, or concatenate/rejoin the volume parts externally before parsing
  2. Check the archive with WinRAR/7-Zip/unrar -v to confirm it is multipart
  3. If you control archive creation, re-create without volume splitting

Example fix

// before
const records = readRar(fs.readFileSync('backup.part1.rar'));
// after
// rejoin volumes first, e.g. `cat backup.part*.rar > backup.rar`, then
const records = readRar(fs.readFileSync('backup.rar'));
Defensive patterns

Strategy: try-catch

Validate before calling

const bytes = new Uint8Array(buf);
// scan for a multi-volume marker is unreliable pre-parse; instead detect via file naming
if (/\.part\d+\.rar$/i.test(path)) throw new Error('multi-volume RAR not supported');

Try / catch

try {
  const records = readRar(bytes);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes('multi-volume')) {
    // fall back to CLI extraction or surface 'multipart archive' to user
  } else throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/00e52e1e2260d1c4. Report an issue: GitHub.