can1357/oh-my-pi · error · ArchiveError

Unsupported RAR5 recovery record

Error message

Unsupported RAR5 recovery record

What it means

The RAR5 main archive header's archive flags bit 8 (RECOVERY) means the archive ends with a recovery record (RR) used to repair damaged archives. The library does not implement recovery-record parsing, so such archives are rejected.

Source

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

		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;
			if ((fileFlags & 2) !== 0) {
				need(cursor.offset, 4, extraStart, "RAR5 modification time");
				mtimeMs = readUInt32LE(bytes, cursor.offset) * 1000;
				cursor.offset += 4;
			}
			let dataCrc: number | undefined;
			if ((fileFlags & 4) !== 0) {
				need(cursor.offset, 4, extraStart, "RAR5 data CRC32");
				dataCrc = readUInt32LE(bytes, cursor.offset);
				cursor.offset += 4;

View on GitHub (pinned to 9690622007)

Solutions

  1. Re-create the archive without the recovery record option
  2. Strip the recovery record with `rar rr` tooling or re-save with WinRAR/unrar
  3. Parse an RR-free copy; the actual file data is unaffected

Example fix

// before
rar a -rr backup.rar files/   // creates RR the parser rejects
// after
rar a backup.rar files/       // no recovery record
Defensive patterns

Strategy: try-catch

Try / catch

try {
  const records = readRar(bytes);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes('recovery record')) {
    logger.warn('RAR has recovery record; parsing not supported');
  } else throw err;
}

Prevention

When it happens

Trigger: Reading a RAR5 archive created with the recovery record option (WinRAR 'Add recovery record', `rar -rr`, or `rar rr` applied afterwards).

Common situations: Archives intended for flaky transfer media (email, Usenet, optical discs); downloaded releases that ship .rev recovery data; backup policies mandating RR.

Related errors


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