can1357/oh-my-pi · error · ArchiveError
Invalid CAB archive: zero-length LZX block
Error message
Invalid CAB archive: zero-length LZX block
What it means
When starting a new LZX block, #readBlockHeader reads a 24-bit block length; a length of zero is illegal because every block must produce at least one byte, so the decoder rejects it instead of looping forever on a no-op block. This indicates a corrupt or malformed bitstream.
Source
Thrown at packages/utils/src/ar/codecs/lzx.ts:231
this.#blockRemaining -= produced;
}
if (this.#blockRemaining === 0 && this.#blockType === 3 && this.#uncompressedPadding) {
reader.readByte();
this.#uncompressedPadding = false;
}
reader.alignWord();
const translated = this.#translateE8(raw);
this.#frame++;
return translated;
}
#readBlockHeader(reader: LzxBitReader): void {
if (this.#blockType === 3 && this.#uncompressedPadding) reader.readByte();
this.#uncompressedPadding = false;
this.#blockType = reader.readBits(3);
this.#blockLength = reader.readBits(16) * 256 + reader.readBits(8);
if (this.#blockLength === 0) throw new ArchiveError("Invalid CAB archive: zero-length LZX block");
this.#blockRemaining = this.#blockLength;
if (this.#blockType === 1 || this.#blockType === 2) {
if (this.#blockType === 2) {
const alignedLengths = new Uint8Array(8);
for (let index = 0; index < alignedLengths.byteLength; index++) alignedLengths[index] = reader.readBits(3);
this.#alignedTable = new LzxHuffmanTable(alignedLengths);
}
readCodeLengths(reader, this.#mainLengths, 0, 256);
readCodeLengths(reader, this.#mainLengths, 256, this.#mainLengths.byteLength);
this.#mainTable = new LzxHuffmanTable(this.#mainLengths);
if (this.#mainLengths[0xe8] !== 0) this.#intelStarted = true;
readCodeLengths(reader, this.#lengthLengths, 0, this.#lengthLengths.byteLength);
this.#lengthTable = new LzxHuffmanTable(this.#lengthLengths, true);
return;
}
if (this.#blockType === 3) {
this.#intelStarted = true;View on GitHub (pinned to 9690622007)
Solutions
- Verify and re-download the CAB archive.
- Recompress with a standard CAB tool so every block has a non-zero length.
- Check frame/block byte boundaries — desync from a prior error can land the reader on padding interpreted as a zero header.
- Never continue using an LzxDecoder instance after a thrown ArchiveError; rebuild it from the folder start.
Example fix
// before decoder.decompressFrame(bytes.slice(4), size) // arbitrary skip desyncs the bitstream // after decoder.decompressFrame(bytes, size) // feed exact CFDATA block bytes; fresh decoder per folder
Defensive patterns
Strategy: try-catch
Try / catch
try {
const out = decoder.decompressFrame(bytes, size)
} catch (err) {
if (err instanceof ArchiveError && err.message.includes('zero-length LZX block')) {
throw new Error('CAB archive corrupt: zero-length LZX block header')
}
throw err
} Prevention
- Validate archive integrity before decoding
- Do not skip or trim bytes within a frame — bit alignment matters
- Restart the folder decode with a fresh LzxDecoder after any ArchiveError
When it happens
Trigger: Decoding a CAB LZX stream whose next block header encodes blockLength = 0 (all 24 length bits zero), typically after bit desync or data truncation.
Common situations: Corrupted or truncated downloads, encoders emitting empty blocks, feeding wrong byte offsets so padding bytes are parsed as a block header.
Related errors
- Invalid CAB archive: empty LZX Huffman tree
- Invalid CAB archive: oversubscribed LZX Huffman tree
- Invalid CAB archive: invalid LZX Huffman symbol
- Invalid CAB archive: LZX code-length run exceeds its tree
- Invalid CAB archive: LZX block produced the wrong byte count
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/2793d75e72bb1ffd.
Report an issue: GitHub.