can1357/oh-my-pi · error · ArchiveError

Encrypted RAR4 headers are not supported

Error message

Encrypted RAR4 headers are not supported

What it means

Flag bit 0x80 on the RAR4 main header (type 0x73) means the archive's header block is encrypted (password-protected file names, set via 'Encrypt file names' in WinRAR). Without the password and AES decryption of headers, no member can even be enumerated, so the parser throws ArchiveError rather than returning garbage.

Source

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

		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;
			let unpackedSize = unpackedLow;

View on GitHub (pinned to 9690622007)

Solutions

  1. Decrypt/extract externally with the password (unrar x -p<password> or 7z x -p<password>) and feed the extracted files to the library.
  2. Ask the archive creator to re-create it without header encryption (uncheck 'Encrypt file names').
  3. Repackage decrypted contents as zip/tar.
  4. Catch ArchiveError and prompt the user for a password / route to an external decryption path.

Example fix

// before
await records(Bun.file("secret.rar")) // header-encrypted
// after
$`unrar x -p$PASS secret.rar out/` // then read out/ files
Defensive patterns

Strategy: try-catch

Try / catch

try {
  const recs = await records(file);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes("Encrypted RAR4 headers")) {
    // obtain password, decrypt via unrar -p<pass>, then reprocess
  } else throw err;
}

Prevention

When it happens

Trigger: Calling records() on a RAR4 archive created with header encryption enabled; the throw happens at the very first main header, before any file entries.

Common situations: Archives shared with 'Encrypt file names' checked and a password; pipelines missing password handling for legacy RAR4; users assuming filename-only listing works without the password.

Related errors


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