can1357/oh-my-pi · error · ArchiveError

Invalid CAB archive: missing LZX aligned tree

Error message

Invalid CAB archive: missing LZX aligned tree

What it means

For aligned-offset blocks (type 2) with >= 3 extra bits, an aligned-offset Huffman tree must exist to decode the low 3 bits of the offset. It is null here, meaning block header setup did not build the aligned tree for this aligned block.

Source

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

			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++) {
				const source = (this.#windowPosition - matchOffset + this.#window.byteLength) % this.#window.byteLength;
				this.#writeByte(this.#window[source]!, output, outputStart + produced + index);
			}
			produced += matchLength;
		}

View on GitHub (pinned to 9690622007)

Solutions

  1. Use the full decompressFrame pipeline so block headers and trees are always built together.
  2. Verify the CAB payload integrity.
  3. Surface ArchiveError; decoding cannot continue without the tree.
Defensive patterns

Strategy: try-catch

Try / catch

try {
  const out = decompressFrame(frame);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes("missing LZX aligned tree")) {
    // header/tree desync — archive corrupt
  } else throw err;
}

Prevention

When it happens

Trigger: decompressFrame -> #decodeRun processes an Aligned (type 2) match with extra >= 3 while #alignedTable is null.

Common situations: Internal state desync after a corrupt header, or a stream where the aligned tree read failed silently earlier.

Related errors


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