can1357/oh-my-pi · error · ArchiveError
Invalid CAB archive: invalid LZX Huffman code length
Error message
Invalid CAB archive: invalid LZX Huffman code length
What it means
LZX Huffman code lengths are at most 16 bits; the LzxHuffmanTable constructor validates every length read from the block header's code-length trees. A value above 16 can only come from a corrupt or hostile bitstream (valid encodings can't produce it via readCodeLengths deltas... but a direct call with a bad lengths array can), so the decoder refuses to build the table.
Source
Thrown at packages/utils/src/ar/codecs/lzx.ts:72
const b0 = this.readByte();
const b1 = this.readByte();
const b2 = this.readByte();
const b3 = this.readByte();
return (b0 | (b1 << 8) | (b2 << 16) | (b3 << 24)) >>> 0;
}
}
class LzxHuffmanTable {
readonly #counts = new Uint32Array(17);
readonly #firstCodes = new Uint32Array(17);
readonly #firstSymbols = new Uint32Array(17);
readonly #symbols: Uint16Array;
readonly empty: boolean;
constructor(lengths: Uint8Array, allowEmpty = false) {
let symbolCount = 0;
for (const length of lengths) {
if (length > 16) throw new ArchiveError("Invalid CAB archive: invalid LZX Huffman code length");
if (length !== 0) {
this.#counts[length]++;
symbolCount++;
}
}
this.empty = symbolCount === 0;
if (this.empty && !allowEmpty) {
throw new ArchiveError("Invalid CAB archive: empty LZX Huffman tree");
}
let code = 0;
let symbolOffset = 0;
for (let length = 1; length <= 16; length++) {
code = (code + this.#counts[length - 1]!) * 2;
if (code + this.#counts[length]! > 2 ** length) {
throw new ArchiveError("Invalid CAB archive: oversubscribed LZX Huffman tree");
}
this.#firstCodes[length] = code;View on GitHub (pinned to 9690622007)
Solutions
- If calling LzxHuffmanTable yourself, clamp/validate lengths to 0..16 before construction.
- If decoding CABs normally, treat the archive as corrupt: validate with cabextract/7z and re-obtain the file.
- Check for stream desync — once a prior frame/block decode fails mid-way, abandon that decoder; create a fresh LzxDecoder per folder.
- Verify readCodeLengths inputs (first/last ranges) match the LZX spec (main tree split at 256, length tree of 249).
Example fix
// before
const table = new LzxHuffmanTable(rawLengths); // rawLengths may contain 17+
// after
const lengths = Uint8Array.from(rawLengths, (n) => n & 0x0f); // or validate explicitly
if (lengths.some((n) => n > 16)) throw new Error("bad lengths");
const table = new LzxHuffmanTable(lengths); Defensive patterns
Strategy: validation
Validate before calling
if (Array.prototype.some.call(lengths, (n) => n > 16)) {
throw new Error("Huffman code length exceeds 16 bits — stream is corrupt");
} Type guard
function hasValidLzxLengths(lengths: Uint8Array): boolean {
for (let i = 0; i < lengths.byteLength; i++) {
if (lengths[i]! > 16) return false;
}
return true;
} Try / catch
try {
return decoder.decompressFrame(frameBytes, outputSize);
} catch (e) {
if (e instanceof Error && e.message.includes("invalid LZX Huffman code length")) {
throw new Error("Block header decoded impossible code lengths — abandon this decoder (state is desynced) and reject the archive");
}
throw e;
} Prevention
- Never construct LzxHuffmanTable from unvalidated lengths in custom tooling; clamp to 0..16 with explicit validation.
- Discard an LzxDecoder after any mid-frame failure — residual bit state poisons later tables.
- Treat this error on otherwise-valid CABs as a sign of upstream corruption; verify with an independent extractor.
When it happens
Trigger: Constructing LzxHuffmanTable directly (or via a corrupted readCodeLengths path) with a Uint8Array containing an entry > 16: feeding pre-tree 4-bit values into the wrong array, a caller-supplied lengths buffer that was never mod-17 reduced, or bit desync corrupting stored lengths.
Common situations: Custom CAB/LZX tooling that builds Huffman tables from unvalidated decoded lengths; fuzzed archives; reusing the decoder after a previous desync so subsequent block headers decode to garbage lengths.
Related errors
- Invalid CAB archive: misaligned LZX byte stream
- Invalid CAB archive: empty LZX Huffman tree
- Invalid CAB archive: oversubscribed LZX Huffman tree
- Invalid CAB archive: LZX stream uses an empty Huffman tree
- Invalid CAB archive: invalid LZX Huffman symbol
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/607a0042abdfbd74.
Report an issue: GitHub.