can1357/oh-my-pi · error · ArchiveError
Invalid CAB archive: invalid LZX Huffman symbol
Error message
Invalid CAB archive: invalid LZX Huffman symbol
What it means
Thrown by LzxHuffmanTable.decode after consuming up to 16 bits without the accumulated code matching any entry in the tree. The bitstream contains a code prefix that no symbol was assigned, which cannot happen with a valid encoder — it indicates corrupt or misaligned data.
Source
Thrown at packages/utils/src/ar/codecs/lzx.ts:114
const next = this.#firstSymbols.slice();
for (let symbol = 0; symbol < lengths.byteLength; symbol++) {
const length = lengths[symbol]!;
if (length !== 0) this.#symbols[next[length]!] = symbol;
next[length]!++;
}
}
decode(reader: LzxBitReader): number {
if (this.empty) throw new ArchiveError("Invalid CAB archive: LZX stream uses an empty Huffman tree");
let code = 0;
for (let length = 1; length <= 16; length++) {
code = code * 2 + reader.readBits(1);
const relative = code - this.#firstCodes[length]!;
if (relative >= 0 && relative < this.#counts[length]!) {
return this.#symbols[this.#firstSymbols[length]! + relative]!;
}
}
throw new ArchiveError("Invalid CAB archive: invalid LZX Huffman symbol");
}
}
function readCodeLengths(reader: LzxBitReader, lengths: Uint8Array, first: number, last: number): void {
const pretreeLengths = new Uint8Array(20);
for (let index = 0; index < pretreeLengths.byteLength; index++) pretreeLengths[index] = reader.readBits(4);
const pretree = new LzxHuffmanTable(pretreeLengths);
let index = first;
while (index < last) {
const symbol = pretree.decode(reader);
if (symbol === 17 || symbol === 18) {
const run = reader.readBits(symbol === 17 ? 4 : 5) + (symbol === 17 ? 4 : 20);
if (index + run > last) throw new ArchiveError("Invalid CAB archive: LZX code-length run exceeds its tree");
lengths.fill(0, index, index + run);
index += run;
continue;
}
if (symbol === 19) {View on GitHub (pinned to 9690622007)
Solutions
- Check that each decompressFrame call receives exactly one CFDATA block's compressed bytes, in order, with matching outputSize.
- Verify the CAB file's integrity and re-download.
- Recompress the archive with a conformant tool.
- Make sure no earlier error path left the decoder mid-frame; a fresh LzxDecoder must be created per folder and reused for the whole folder only.
Example fix
// before
for (const block of blocks) decoder.decompressFrame(block.compressed, block.uncompressedSize)
// after
let decoder: LzxDecoder | null = null
for (const block of blocks) {
decoder ??= new LzxDecoder(folder.windowBits)
decoder.decompressFrame(block.compressed, block.uncompressedSize) // same decoder per folder, exact block bytes
} Defensive patterns
Strategy: try-catch
Validate before calling
// Ensure frame boundaries are exact before decoding:
if (!Number.isInteger(size) || size <= 0 || size > 32768) throw new Error('bad frame size')
if (bytes.byteLength === 0) throw new Error('empty frame data') Try / catch
try {
const frame = decoder.decompressFrame(blockData, blockOutSize)
} catch (err) {
if (err instanceof ArchiveError && err.message.includes('invalid LZX Huffman symbol')) {
throw new Error('CAB data is corrupt or frames were fed out of order')
}
throw err
} Prevention
- Feed CFDATA blocks strictly in order with exact byte slices
- Use a fresh LzxDecoder for each CAB folder
- Never reuse a decoder instance after an error
- Verify archive checksums before decompression
When it happens
Trigger: Decoding any LZX symbol (main, length, aligned, or pretree) when the reader is bit-desynchronized or the data is corrupt, so the next bits do not form a valid code prefix.
Common situations: Truncated or bit-rotted CAB downloads, wrong slice boundaries passed to decompressFrame (frames must be fed in order with exact CFDATA uncompressed-block sizes), decoding non-CAB LZX data with this CAB-specific decoder.
Related errors
- Invalid CAB archive: empty LZX Huffman tree
- Invalid CAB archive: oversubscribed LZX Huffman tree
- Invalid CAB archive: LZX code-length run exceeds its tree
- Invalid CAB archive: invalid LZX Huffman code length
- Invalid CAB archive: LZX stream uses an empty Huffman tree
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/70ac325387e9e164.
Report an issue: GitHub.