can1357/oh-my-pi · error · ArchiveError

Encrypted RAR4 file data is not supported

Error message

Encrypted RAR4 file data is not supported

What it means

Flag bit 2 (0x4) on a RAR4 file header marks the member's packed data as encrypted with a password (AES). The library does not implement RAR crypto decryption, so any encrypted member causes an immediate ArchiveError. Non-encrypted members in the same archive can still be parsed only if no encrypted member is hit first in header order.

Source

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

			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;
			if ((flags & 0x100) !== 0) {
				need(cursor, 8, headerEnd, "RAR4 high sizes");
				packedSize += readUInt32LE(bytes, cursor) * 0x100000000;
				cursor += 4;
				unpackedSize += readUInt32LE(bytes, cursor) * 0x100000000;
				cursor += 4;
				dataEnd = checkedEnd(dataStart, packedSize, bytes.byteLength, "RAR4 file data");
			}
			if ((flags & 3) !== 0) throw new ArchiveError("Unsupported multi-volume RAR4 member");
			if ((flags & 4) !== 0) throw new ArchiveError("Encrypted RAR4 file data is not supported");
			if (methodByte < 0x30 || methodByte > 0x35)
				throw new ArchiveError(`Unsupported RAR4 compression method 0x${methodByte.toString(16)}`);
			assertArchivePathBytes(nameSize, "member path", options.limits.maxPathBytes);
			need(cursor, nameSize, headerEnd, "RAR4 file name");
			const nameBytes = bytes.subarray(cursor, cursor + nameSize);
			const rawPath = (flags & 0x200) !== 0 ? decodeRar4UnicodeName(nameBytes) : LATIN1.decode(nameBytes);
			cursor += nameSize;
			if ((flags & 0x400) !== 0) {
				need(cursor, 8, headerEnd, "RAR4 salt");
				cursor += 8;
			}
			let mtimeMs = dosTimeMs(dosTime);
			if ((flags & 0x1000) !== 0) {
				need(cursor, 2, headerEnd, "RAR4 extended time flags");
				const timeFlags = readUInt16LE(bytes, cursor);
				cursor += 2;
				for (let timeIndex = 0; timeIndex < 4; timeIndex++) {
					const mode = (timeFlags >>> ((3 - timeIndex) * 4)) & 15;

View on GitHub (pinned to 9690622007)

Solutions

  1. Decrypt externally with the password: unrar x -p<password> or 7z x -p<password>, then process the extracted files.
  2. Have the archive creator re-pack without a password.
  3. Repackage decrypted content as zip/tar.
  4. Catch ArchiveError and prompt for a password, routing to an external decryption path.

Example fix

// before
await records(Bun.file("locked.rar"))
// after
$`7z x -p$PASS locked.rar -oout/` // then read out/
Defensive patterns

Strategy: try-catch

Try / catch

try {
  const recs = await records(file);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes("Encrypted RAR4 file data")) {
    // decrypt with password via external tool, then reprocess
  } else throw err;
}

Prevention

When it happens

Trigger: Calling records() on a password-protected RAR4 archive (WinRAR 'Set password'); throws at the first encrypted file header during enumeration.

Common situations: User-supplied archives protected with a password; CI pipelines lacking the password; archives where only some members are encrypted.

Related errors


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