can1357/oh-my-pi · error · ArchiveError

RAR5 member with unknown unpacked size is not supported

Error message

RAR5 member with unknown unpacked size is not supported

What it means

RAR5 file header flag bit 8 (UNPACKED_SIZE_UNKNOWN) indicates the member's unpacked size was not stored — the decoder must discover it while decompressing (streaming mode). This library needs the size up front to bound memory and validate limits, so it rejects such members.

Source

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

		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;
			}
			const compression = readVint(bytes, cursor, extraStart, "compression information");
			let version = compression & 0x3f;
			if (version === 1 && (compression & 0x100000) !== 0) version = 0;
			const solid = (compression & 0x40) !== 0;
			const method = (compression >>> 7) & 7;

View on GitHub (pinned to 9690622007)

Solutions

  1. Re-create the archive from files on disk so sizes are stored (avoid `-si` streaming input)
  2. Extract with the unrar CLI and re-compress normally
  3. Inspect the offending member with `unrar l -v` to identify the streaming-produced entry

Example fix

// before
tar c dir/ | rar a -si archive.rar   # unknown sizes -> rejected
// after
rar a archive.rar dir/               # sizes stored in headers
Defensive patterns

Strategy: validation

Try / catch

try {
  const records = readRar(bytes);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes('unknown unpacked size')) {
    // re-extract via unrar CLI which supports streaming members
  } else throw err;
}

Prevention

When it happens

Trigger: Parsing a RAR5 archive whose file/dir header (type 2 or 3) has fileFlags bit 0x8 set, typically produced by streaming/piped compression where the size is unknown at header write time.

Common situations: Archives generated by tools piping data into rar (`tar c | rar a -si`), which omits sizes; unusual third-party RAR writers; archives rebuilt by scripts that stream content.

Related errors


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