can1357/oh-my-pi · error · ArchiveError
Invalid CAB archive: truncated LZX bitstream
Error message
Invalid CAB archive: truncated LZX bitstream
What it means
The LZX bit reader refills from the CAB CFDATA block two bytes at a time; this error means it needed more bits but the input buffer ran out. The compressed data block is truncated relative to what the stream's decoded output requires — either the CFDATA block was cut short or the caller passed fewer bytes than the block header promises (cbCompressed).
Source
Thrown at packages/utils/src/ar/codecs/lzx.ts:25
const POSITION_SLOTS = [30, 32, 34, 36, 38, 42, 50] as const;
class LzxBitReader {
readonly #bytes: Uint8Array;
#offset = 0;
#word = 0;
#remaining = 0;
constructor(bytes: Uint8Array) {
this.#bytes = bytes;
}
readBits(count: number): number {
let value = 0;
let needed = count;
while (needed > 0) {
if (this.#remaining === 0) {
if (this.#offset + 2 > this.#bytes.byteLength) {
throw new ArchiveError("Invalid CAB archive: truncated LZX bitstream");
}
this.#word = this.#bytes[this.#offset]! | (this.#bytes[this.#offset + 1]! << 8);
this.#offset += 2;
this.#remaining = 16;
}
const take = Math.min(needed, this.#remaining);
value = value * 2 ** take + ((this.#word >>> (this.#remaining - take)) & (2 ** take - 1));
this.#remaining -= take;
needed -= take;
}
return value;
}
alignWord(): void {
this.#remaining = 0;
}
readByte(): number {View on GitHub (pinned to 9690622007)
Solutions
- Pass the full CFDATA block bytes for the frame — exactly cbCompressed bytes as declared in the CAB header, read contiguously.
- Verify the CAB file is complete (file size vs. total declared blocks) and re-download if truncated.
- If the folder spans multiple data blocks, concatenate/reserve the folder's compressed data before decoding frames rather than feeding partial buffers.
- Validate your CAB parser's cbCompressed/cbUncompressed accounting against the remaining file length.
Example fix
// before const frame = cabData.subarray(0, guessed); // guessed too small const out = decoder.decompressFrame(frame, 32768); // after const frame = cabData.subarray(offset, offset + cfdatum.cbCompressed); const out = decoder.decompressFrame(frame, cfdatum.cbUncompressed);
Defensive patterns
Strategy: validation
Validate before calling
if (cfdatum.cbCompressed > data.byteLength - offset) {
throw new Error(`CAB truncated: need ${cfdatum.cbCompressed} bytes at ${offset}, have ${data.byteLength - offset}`);
}
const frame = data.subarray(offset, offset + cfdatum.cbCompressed); Type guard
function hasFullCfdataBlock(data: Uint8Array, offset: number, cbCompressed: number): boolean {
return offset >= 0 && cbCompressed >= 0 && offset + cbCompressed <= data.byteLength;
} Try / catch
try {
return decoder.decompressFrame(frame, outputSize);
} catch (e) {
if (e instanceof Error && e.message.includes("truncated LZX bitstream")) {
throw new Error("CFDATA block shorter than declared — CAB file is truncated or misparsed");
}
throw e;
} Prevention
- Slice frames using the header-declared cbCompressed, never guessed chunk sizes.
- Check total CAB file size against summed block sizes before extraction.
- Verify partial downloads complete (Content-Length vs actual bytes) before parsing.
When it happens
Trigger: Calling LzxDecoder.decompressFrame(bytes, outputSize) with a bytes buffer shorter than the frame's compressed size: reading CFDATA blocks with a wrong cbCompressed value, slicing the archive incorrectly, or a corrupt CAB whose data block length field doesn't match actual stored bytes.
Common situations: Partial downloads of .cab files; custom CAB parsers passing only part of a multi-block folder's data; corrupted archives; using the LZX decoder directly with per-block buffers when the caller accumulated the wrong byte counts.
Related errors
- Invalid CAB archive: truncated LZX data
- Invalid CAB archive: truncated CFDATA payload
- Invalid CAB archive: misaligned LZX byte stream
- Invalid CAB archive: invalid LZX Huffman code length
- Invalid CAB archive: empty LZX Huffman tree
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/eb97a419405c4f3d.
Report an issue: GitHub.