can1357/oh-my-pi · error · ArchiveError

Unsupported RAR4 recovery record

Error message

Unsupported RAR4 recovery record

What it means

The RAR4 main header (type 0x73) with flag bit 0x40 indicates an auxiliary recovery record attached to the archive. parseRar4 does not implement recovery records, so it refuses the archive with ArchiveError. Like the RAR5 RR case, recovery data is repair redundancy, not file content.

Source

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

		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;
			let packedSize = dataSize;

View on GitHub (pinned to 9690622007)

Solutions

  1. Re-create the archive without a recovery record (omit -rr in rar).
  2. Open and re-save the archive in WinRAR with recovery record removed.
  3. Extract with unrar/7-Zip externally and repackage as zip/tar for this library.
  4. Catch ArchiveError and fall back to an external extractor.

Example fix

// before
$`rar a -rr archive.rar files/`
// after
$`rar a archive.rar files/`
Defensive patterns

Strategy: try-catch

Validate before calling

// Cannot read the main-header flags before parsing; guard by re-packing policy:
// if archives come from an untrusted source, test-parse and handle ArchiveError.

Try / catch

try {
  const recs = await records(file);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes("RAR4 recovery record")) {
    // strip recovery record via WinRAR or extract externally
  } else throw err;
}

Prevention

When it happens

Trigger: Calling records() on a RAR4 archive created with 'Add recovery record' enabled (WinRAR -rr, flag 0x40 in the main header).

Common situations: Legacy archives distributed with recovery data for usenet/email transfer; archives protected against bit-rot by the sender; re-shared archives that kept the flag.

Related errors


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