can1357/oh-my-pi · error · ArchiveError

Bzip2 block exceeds its declared block-size level

Error message

Bzip2 block exceeds its declared block-size level

What it means

bzip2 blocks declare a block-size level (100KB–900KB). The decoder enforces that RLE2 'append(byte, count)' never pushes total block output past that declared limit. This error fires when a decoded BWT/RLE run length would overflow the declared block size — the stream contradicts its own header.

Source

Thrown at packages/utils/src/ar/codecs/bzip2.ts:293

	let selectorIndex = 0;
	let groupRemaining = 0;
	let table: HuffmanTable | undefined;

	const nextSymbol = (): number => {
		if (groupRemaining === 0) {
			if (selectorIndex >= selectors.length) {
				throw new ArchiveError("Bzip2 block exhausted its Huffman selectors");
			}
			table = tables[selectors[selectorIndex++]!];
			groupRemaining = GROUP_SIZE;
		}
		groupRemaining--;
		return table!.decode(reader);
	};

	const append = (byte: number, count: number): void => {
		if (count < 0 || blockLength + count > blockSizeLimit) {
			throw new ArchiveError("Bzip2 block exceeds its declared block-size level");
		}
		block.fill(byte, blockLength, blockLength + count);
		blockLength += count;
	};

	const endSymbol = usedBytes.length + 1;
	let symbol = nextSymbol();
	while (symbol !== endSymbol) {
		if (symbol === 0 || symbol === 1) {
			let runLength = 0;
			let power = 1;
			do {
				runLength += symbol === 0 ? power : power * 2;
				if (runLength > blockSizeLimit || power > blockSizeLimit) {
					throw new ArchiveError("Invalid bzip2 RLE run length");
				}
				power *= 2;
				symbol = nextSymbol();

View on GitHub (pinned to 9690622007)

Solutions

  1. Test the archive with `bzip2 -t` and replace the corrupted file.
  2. Confirm the input passed to the decompressor starts at the 'BZh' magic — an offset stream misaligns the header and block sizes.
  3. If concatenating/dealing with multi-stream bz2, split on the proper stream end marker rather than arbitrary offsets.
  4. If this happens on trusted data, report/log the byte offset; this indicates an encoder or library bug.

Example fix

// before: offset slice skipping the BZh header
const body = bytes.subarray(4);
decompressBzip2(body);
// after: include the full stream with its header
decompressBzip2(bytes);
Defensive patterns

Strategy: try-catch

Validate before calling

const header = new TextDecoder().decode(bytes.subarray(0, 3));
if (header !== "BZh" || !(bytes[3]! >= 0x31 && bytes[3]! <= 0x39)) throw new Error("Not a bzip2 stream");

Try / catch

try {
  return decompressBzip2(bytes);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes("block-size")) {
    throw new Error("bzip2 block data contradicts its header — archive is corrupt", { cause: err });
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling append (from decodeBlockData) with a computed run count that is negative (corrupt RUNA/RUNB sequence) or pushes blockLength beyond blockSizeLimit, i.e. a corrupt bzip2 block or a mismatched blockSizeLimit derived from the stream header ('BZh9' etc.).

Common situations: Decoding damaged .bz2 data; a stream whose header level digit was altered; feeding bytes from one block into a decoder initialized for another; fuzzing/maliciously crafted archives.

Related errors


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