can1357/oh-my-pi · error · ArchiveError
Invalid CAB archive: LZX frame size ${outputSize} exceeds 32
Error message
Invalid CAB archive: LZX frame size ${outputSize} exceeds 32768 bytes What it means
CAB LZX frames decode at most FRAME_SIZE (32768) bytes each; decompressFrame validates outputSize is a non-negative integer within that bound before decoding. A larger request means the caller split frames incorrectly or the folder metadata is corrupt.
Source
Thrown at packages/utils/src/ar/codecs/lzx.ts:192
constructor(windowBits: number) {
if (!Number.isInteger(windowBits) || windowBits < 15 || windowBits > 21) {
throw new ArchiveError(`Unsupported CAB LZX window size: ${windowBits} bits (expected 15-21)`);
}
this.#window = new Uint8Array(2 ** windowBits);
const slots = POSITION_SLOTS[windowBits - 15]!;
this.#mainLengths = new Uint8Array(256 + slots * 8);
this.#extraBits = new Uint8Array(slots);
this.#positionBase = new Uint32Array(slots);
for (let slot = 0; slot < slots; slot++) {
this.#extraBits[slot] = slot < 4 ? 0 : Math.min(17, Math.floor(slot / 2) - 1);
if (slot > 0) this.#positionBase[slot] = this.#positionBase[slot - 1]! + 2 ** this.#extraBits[slot - 1]!;
}
}
/** Decode one CAB CFDATA LZX frame while preserving the folder's dictionary and Huffman state. */
decompressFrame(bytes: Uint8Array, outputSize: number): Uint8Array {
if (!Number.isInteger(outputSize) || outputSize < 0 || outputSize > FRAME_SIZE) {
throw new ArchiveError(`Invalid CAB archive: LZX frame size ${outputSize} exceeds 32768 bytes`);
}
if (outputSize === 0) return new Uint8Array(0);
const reader = new LzxBitReader(bytes);
if (!this.#headerRead) {
if (reader.readBits(1) !== 0) {
const high = reader.readBits(16);
const low = reader.readBits(16);
this.#intelFileSize = signedUInt32((high * 0x10000 + low) >>> 0);
}
this.#headerRead = true;
}
const raw = new Uint8Array(outputSize);
let outputPosition = 0;
while (outputPosition < outputSize) {
if (this.#blockRemaining === 0) this.#readBlockHeader(reader);
const run = Math.min(this.#blockRemaining, outputSize - outputPosition);
const produced = this.#decodeRun(reader, raw, outputPosition, run);View on GitHub (pinned to 9690622007)
Solutions
- Call decompressFrame once per CFDATA block with that block's own uncompressed size (max 32768).
- Split larger outputs into successive 32 KiB frames, reusing the same LzxDecoder to preserve dictionary state.
- Validate outputSize with Number.isInteger(size) && size >= 0 && size <= 32768 before calling.
- Sanity-check the folder's block sizes against the CAB header; nonsensical sizes indicate corruption.
Example fix
// before decoder.decompressFrame(block.data, folder.totalUncompressedSize) // after decoder.decompressFrame(block.data, block.uncompressedSize) // one CFDATA block per call, ≤ 32768
Defensive patterns
Strategy: validation
Validate before calling
function assertValidFrameSize(outputSize: number): void {
if (!Number.isInteger(outputSize) || outputSize < 0 || outputSize > 32768) {
throw new Error(`Frame output size must be an integer in [0, 32768], got ${outputSize}`)
}
}
assertValidFrameSize(block.uncompressedSize) Type guard
function isValidFrameSize(v: unknown): v is number {
return typeof v === 'number' && Number.isInteger(v) && v >= 0 && v <= 32768
} Try / catch
try {
return decoder.decompressFrame(data, outputSize)
} catch (err) {
if (err instanceof ArchiveError && err.message.includes('frame size')) {
throw new Error('Frame split error: call decompressFrame once per CFDATA block (≤32768 bytes)')
}
throw err
} Prevention
- One decompressFrame call per CFDATA block, using that block's own uncompressed size
- Reuse the decoder across frames of the same folder to preserve window state
- Cross-check block sizes against the CAB folder header for corruption
When it happens
Trigger: decoder.decompressFrame(bytes, 40000), passing a negative or non-integer outputSize, or summing multiple CFDATA blocks' uncompressed sizes into one call instead of one call per block.
Common situations: Misreading CFDATA cbUncompressed (which can exceed 32768 only across folder boundaries), feeding an entire folder's data to a single frame call, integer parse errors from archive metadata.
Understand the failure class
Background: "must be positive", "Invalid value": how libraries reject invalid parameter values (ValueError, ArgumentError, INVALID_PARAMETER_VALUE) — this error's family across 28 libraries.
Related errors
- Unsupported CAB LZX window size: ${windowBits} bits (expecte
- Invalid CAB archive: truncated data
- Invalid CAB archive: file has an invalid DOS timestamp
- Unsupported CAB LZX window size: ${description.parameter} bi
- Invalid CAB archive: CFDATA expands to ${uncompressed} bytes
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/09636e87e6060413.
Report an issue: GitHub.