can1357/oh-my-pi · error · ArchiveError

Archive is too large to read safely

Error message

Archive is too large to read safely

What it means

readRar() validates source.size before doing any work: it must be a non-negative safe integer. Otherwise the sparse-read strategy (which allocates based on size) would be unsafe, so it throws 'Archive is too large to read safely'.

Source

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

			}
			if (output.byteLength !== record.unpackedSize) corrupt(`member '${record.path}' size mismatch`);
			if (record.crc !== undefined && crc32(output) !== record.crc) {
				throw new ArchiveError(`RAR member '${record.path}' CRC32 mismatch`);
			}
			this.#cache.set(current, output.slice());
		}
	}
}

/** Probe the RAR 1.5-4.x or RAR5 signature. */
export function sniffRar(bytes: Uint8Array): boolean {
	return findMarker(bytes) !== undefined;
}

/** Index a RAR4 or RAR5 archive and defer member decompression until extraction. */
export const readRar: FormatReader = async (source, options) => {
	if (!Number.isSafeInteger(source.size) || source.size < 0) {
		throw new ArchiveError("Archive is too large to read safely");
	}
	const indexed = await indexRarMetadata(source, options);
	const bytes = sparseBytes(source.size, indexed.segments);
	const marker = indexed.marker;
	const records =
		marker.version === 5 ? parseRar5(bytes, marker.offset, options) : parseRar4(bytes, marker.offset, options);
	const archive = new RarArchive(source, records, options);
	const entries: ArchiveIndexEntry[] = [];
	for (let index = 0; index < records.length; index++) {
		const record = records[index]!;
		const entry: ArchiveIndexEntry = {
			path: record.path,
			isDirectory: record.isDirectory,
			size: record.unpackedSize,
		};
		if (record.mtimeMs !== undefined) entry.mtimeMs = record.mtimeMs;
		if (record.mode !== undefined) entry.mode = record.mode;
		if (record.linkTarget !== undefined) {

View on GitHub (pinned to 9690622007)

Solutions

  1. Ensure the Source has an accurate numeric size before calling readRar (stat the file and populate source.size)
  2. If the source is a stream of unknown length, buffer it to a file first and index from that
  3. Sanitize the size you report (0 <= size <= MAX_SAFE_INTEGER)

Example fix

// before
await readRar({ size: file.size ?? -1, read }, options);
// after
const stat = await fs.stat(path);
await readRar({ size: stat.size, read }, options);
Defensive patterns

Strategy: validation

Validate before calling

if (!Number.isSafeInteger(source.size) || source.size < 0) {
  throw new Error('Source size must be a non-negative safe integer before calling readRar');
}

Type guard

function hasValidSize(source: { size: unknown }): source is { size: number } {
  return typeof source.size === 'number' && Number.isSafeInteger(source.size) && source.size >= 0;
}

Try / catch

try {
  const reader = await readRar(source, options);
} catch (err) {
  if (err instanceof ArchiveError && err.message === 'Archive is too large to read safely') {
    throw new Error('Provide a source with a known, non-negative integer size');
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling readRar(source, options) where source.size is undefined, negative, fractional, or exceeds Number.MAX_SAFE_INTEGER — e.g. a Blob/File with unknown size, a streaming source reporting -1, or a bogus stat.

Common situations: Passing a handle to a pipe/device whose size is unknown; using a custom Source implementation that doesn't populate size; 32-bit overflow artifacts in metadata.

Related errors


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