can1357/oh-my-pi · error · ArchiveError

Unsupported multi-volume RAR4 archive

Error message

Unsupported multi-volume RAR4 archive

What it means

In parseRar4, the main archive header (type 0x73) with flag bit 0 set marks a multi-volume (split) RAR4 archive. The library does not support volume sets, so it throws ArchiveError immediately at the main header. Each member's continuation lives in other volume files, which the parser cannot resolve.

Source

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

		const headerCrc = readUInt16LE(bytes, offset);
		const type = bytes[offset + 2]!;
		const flags = readUInt16LE(bytes, offset + 3);
		const headerSize = readUInt16LE(bytes, offset + 5);
		if (headerSize < 7) corrupt("invalid RAR4 header size");
		assertIndexSize(headerSize, options.limits, "RAR4 header");
		const headerEnd = checkedEnd(offset, headerSize, bytes.byteLength, "RAR4 header");
		if ((crc32(bytes.subarray(offset + 2, headerEnd)) & 0xffff) !== headerCrc) corrupt("RAR4 header CRC mismatch");
		let dataSize = 0;
		let cursor = offset + 7;
		if ((flags & 0x8000) !== 0) {
			need(cursor, 4, headerEnd, "RAR4 additional size");
			dataSize = readUInt32LE(bytes, cursor);
			cursor += 4;
		}
		const dataStart = headerEnd;
		let dataEnd = checkedEnd(dataStart, dataSize, bytes.byteLength, "RAR4 data area");
		if (type === 0x73) {
			if ((flags & 1) !== 0) throw new ArchiveError("Unsupported multi-volume RAR4 archive");
			if ((flags & 0x40) !== 0) throw new ArchiveError("Unsupported RAR4 recovery record");
			if ((flags & 0x80) !== 0) throw new ArchiveError("Encrypted RAR4 headers are not supported");
			sawMain = true;
		} else if (type === 0x74) {
			need(cursor, 21, headerEnd, "RAR4 file header");
			const unpackedLow = readUInt32LE(bytes, cursor);
			cursor += 4;
			const hostOs = bytes[cursor++]!;
			const dataCrc = readUInt32LE(bytes, cursor);
			cursor += 4;
			const dosTime = readUInt32LE(bytes, cursor);
			cursor += 4;
			const version = bytes[cursor++]!;
			const methodByte = bytes[cursor++]!;
			const nameSize = readUInt16LE(bytes, cursor);
			cursor += 2;
			const attributes = readUInt32LE(bytes, cursor);
			cursor += 4;

View on GitHub (pinned to 9690622007)

Solutions

  1. Extract the full volume set with an external tool (unrar/7-Zip) that supports volumes, then consume the extracted files.
  2. Re-create the archive as a single volume without the -v flag.
  3. Repackage contents as zip or tar before parsing with this library.
  4. Catch ArchiveError, detect the multi-volume case, and surface a message asking for all volumes.

Example fix

// before: feeding volume set
await records(Bun.file("old.rar")) // part of .r00/.r01 set
// after: repackage single-volume
$`unrar x -y old.rar extracted/`
Defensive patterns

Strategy: try-catch

Validate before calling

// RAR4 multi-volume main-header flag bit 0 — pre-scan after 7-byte marker
// simplest: reject .rar files that have sibling .r00/.r01/.partN files
import { readdirSync } from "node:fs";
const siblings = readdirSync(dirname).filter(f => /\.r\d{2}$|\.part\d+\.rar$/i.test(f));
if (siblings.length) throw new Error("multi-volume set detected");

Try / catch

try {
  const recs = await records(file);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes("multi-volume RAR4")) {
    // extract full set with unrar, then continue
  } else throw err;
}

Prevention

When it happens

Trigger: Calling records()/parseRar4() on a legacy .rar/.r00/.r01 volume set or the first volume of an old-style split archive.

Common situations: Old archives split to fit floppies/CDs or email limits; extracting only the .rar part without merging; automated pipelines fed a single volume.

Related errors


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