can1357/oh-my-pi · error · ArchiveError

Unsupported CAB LZX window size: ${windowBits} bits (expecte

Error message

Unsupported CAB LZX window size: ${windowBits} bits (expected 15-21)

What it means

The LzxDecoder constructor only supports CAB LZX window sizes from 2^15 (32 KiB) to 2^21 (2 MiB) bits, as used by CAB folders (the cabinet format stores the window bits minus 15 in the folder header). Passing a non-integer or out-of-range windowBits is rejected before any allocation, since the position-slot tables are only defined for 15-21.

Source

Thrown at packages/utils/src/ar/codecs/lzx.ts:176

	#lengthTable?: LzxHuffmanTable;
	#alignedTable?: LzxHuffmanTable;
	#windowPosition = 0;
	#decodedSize = 0;
	#frame = 0;
	#r0 = 1;
	#r1 = 1;
	#r2 = 1;
	#headerRead = false;
	#intelFileSize = 0;
	#intelStarted = false;
	#blockType = 0;
	#blockLength = 0;
	#blockRemaining = 0;
	#uncompressedPadding = false;

	constructor(windowBits: number) {
		if (!Number.isInteger(windowBits) || windowBits < 15 || windowBits > 21) {
			throw new ArchiveError(`Unsupported CAB LZX window size: ${windowBits} bits (expected 15-21)`);
		}
		this.#window = new Uint8Array(2 ** windowBits);
		const slots = POSITION_SLOTS[windowBits - 15]!;
		this.#mainLengths = new Uint8Array(256 + slots * 8);
		this.#extraBits = new Uint8Array(slots);
		this.#positionBase = new Uint32Array(slots);
		for (let slot = 0; slot < slots; slot++) {
			this.#extraBits[slot] = slot < 4 ? 0 : Math.min(17, Math.floor(slot / 2) - 1);
			if (slot > 0) this.#positionBase[slot] = this.#positionBase[slot - 1]! + 2 ** this.#extraBits[slot - 1]!;
		}
	}

	/** Decode one CAB CFDATA LZX frame while preserving the folder's dictionary and Huffman state. */
	decompressFrame(bytes: Uint8Array, outputSize: number): Uint8Array {
		if (!Number.isInteger(outputSize) || outputSize < 0 || outputSize > FRAME_SIZE) {
			throw new ArchiveError(`Invalid CAB archive: LZX frame size ${outputSize} exceeds 32768 bytes`);
		}
		if (outputSize === 0) return new Uint8Array(0);

View on GitHub (pinned to 9690622007)

Solutions

  1. Pass windowBits = rawHeaderValue + 15 when reading a CAB folder header (the stored value is 0-6).
  2. Clamp or validate windowBits to an integer 15-21 before constructing.
  3. If the stream is not CAB LZX, use a decoder for that container's LZX variant instead.
  4. Default to 15 (32 KiB) only when the format genuinely omits the field.

Example fix

// before
const decoder = new LzxDecoder(folder.compressionMemory)
// after
const decoder = new LzxDecoder(folder.windowBits + 15) // header stores windowBits - 15 (0..6)
Defensive patterns

Strategy: validation

Validate before calling

function toWindowBits(storedBits: number): number {
  const windowBits = storedBits + 15 // CAB folder header stores windowBits - 15
  if (!Number.isInteger(windowBits) || windowBits < 15 || windowBits > 21) {
    throw new Error(`Invalid window bits ${storedBits} in CAB folder header`)
  }
  return windowBits
}
const decoder = new LzxDecoder(toWindowBits(folder.headerValue))

Type guard

function isValidWindowBits(v: unknown): v is number {
  return typeof v === 'number' && Number.isInteger(v) && v >= 15 && v <= 21
}

Try / catch

try {
  const decoder = new LzxDecoder(folder.windowBits + 15)
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes('window size')) {
    throw new Error(`Unsupported CAB LZX window bits in folder header: ${folder.windowBits}`)
  }
  throw err
}

Prevention

When it happens

Trigger: new LzxDecoder(14), new LzxDecoder(22), new LzxDecoder(16.5), or new LzxDecoder(NaN) — typically from misreading the CAB folder header's window bits field, which is stored as (windowBits - 15).

Common situations: Passing the raw folder-header byte instead of adding 15, feeding LZX streams from other container formats (e.g. MSI/DIET variants) that use different window conventions, typos in configuration.

Understand the failure class

Background: "must be positive", "Invalid value": how libraries reject invalid parameter values (ValueError, ArgumentError, INVALID_PARAMETER_VALUE) — this error's family across 28 libraries.

Related errors


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