can1357/oh-my-pi · error · ArchiveError

Invalid CAB archive: LZX position slot is out of range

Error message

Invalid CAB archive: LZX position slot is out of range

What it means

The decoded match's position slot indexes beyond the precomputed positionBase/extraBits tables. Valid LZX position slots are bounded by the window size; an out-of-range slot means the Huffman-decoded symbol stream is corrupt.

Source

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

			if (matchLength > count - produced || matchLength > this.#blockRemaining - produced) {
				throw new ArchiveError("Invalid CAB archive: LZX match crosses a frame or block boundary");
			}

			const slot = match >>> 3;
			let matchOffset: number;
			if (slot === 0) {
				matchOffset = this.#r0;
			} else if (slot === 1) {
				matchOffset = this.#r1;
				this.#r1 = this.#r0;
				this.#r0 = matchOffset;
			} else if (slot === 2) {
				matchOffset = this.#r2;
				this.#r2 = this.#r0;
				this.#r0 = matchOffset;
			} else {
				if (slot >= this.#positionBase.byteLength)
					throw new ArchiveError("Invalid CAB archive: LZX position slot is out of range");
				const extra = this.#extraBits[slot]!;
				matchOffset = this.#positionBase[slot]! - 2;
				if (this.#blockType === 2 && extra >= 3) {
					if (extra > 3) matchOffset += reader.readBits(extra - 3) * 8;
					if (!this.#alignedTable) throw new ArchiveError("Invalid CAB archive: missing LZX aligned tree");
					matchOffset += this.#alignedTable.decode(reader);
				} else if (extra !== 0) {
					matchOffset += reader.readBits(extra);
				}
				this.#r2 = this.#r1;
				this.#r1 = this.#r0;
				this.#r0 = matchOffset;
			}

			if (matchOffset <= 0 || matchOffset > Math.min(this.#decodedSize, this.#window.byteLength)) {
				throw new ArchiveError("Invalid CAB archive: LZX match offset exceeds available history");
			}
			for (let index = 0; index < matchLength; index++) {

View on GitHub (pinned to 9690622007)

Solutions

  1. Re-validate/re-download the CAB archive.
  2. Confirm the window size used to initialize the decoder matches the folder's LZX window bits.
  3. Treat as unrecoverable corruption and surface ArchiveError.
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure decoder window matches folder params
function windowBitsValid(windowBits) { return windowBits >= 15 && windowBits <= 23; }

Try / catch

try {
  const out = decompressFrame(frame);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes("position slot")) {
    // bitstream desync or unsupported window — treat file as corrupt
  } else throw err;
}

Prevention

When it happens

Trigger: decompressFrame -> #decodeRun computes slot = match >>> 3 and slot >= positionBase.byteLength for a non-repeated-offset match.

Common situations: Corrupt CAB payloads or bitstream desync causing garbage Huffman symbols; archives compressed with parameters the decoder doesn't expect.

Related errors


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