{"record":{"id":"29504d0046bb4b27","repo":"can1357/oh-my-pi","slug":"unsupported-cab-lzx-window-size-windowbits-bit","errorCode":null,"errorMessage":"Unsupported CAB LZX window size: ${windowBits} bits (expected 15-21)","messagePattern":"Unsupported CAB LZX window size: (.+?) bits \\(expected 15-21\\)","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/codecs/lzx.ts","lineNumber":176,"sourceCode":"\t#lengthTable?: LzxHuffmanTable;\n\t#alignedTable?: LzxHuffmanTable;\n\t#windowPosition = 0;\n\t#decodedSize = 0;\n\t#frame = 0;\n\t#r0 = 1;\n\t#r1 = 1;\n\t#r2 = 1;\n\t#headerRead = false;\n\t#intelFileSize = 0;\n\t#intelStarted = false;\n\t#blockType = 0;\n\t#blockLength = 0;\n\t#blockRemaining = 0;\n\t#uncompressedPadding = false;\n\n\tconstructor(windowBits: number) {\n\t\tif (!Number.isInteger(windowBits) || windowBits < 15 || windowBits > 21) {\n\t\t\tthrow new ArchiveError(`Unsupported CAB LZX window size: ${windowBits} bits (expected 15-21)`);\n\t\t}\n\t\tthis.#window = new Uint8Array(2 ** windowBits);\n\t\tconst slots = POSITION_SLOTS[windowBits - 15]!;\n\t\tthis.#mainLengths = new Uint8Array(256 + slots * 8);\n\t\tthis.#extraBits = new Uint8Array(slots);\n\t\tthis.#positionBase = new Uint32Array(slots);\n\t\tfor (let slot = 0; slot < slots; slot++) {\n\t\t\tthis.#extraBits[slot] = slot < 4 ? 0 : Math.min(17, Math.floor(slot / 2) - 1);\n\t\t\tif (slot > 0) this.#positionBase[slot] = this.#positionBase[slot - 1]! + 2 ** this.#extraBits[slot - 1]!;\n\t\t}\n\t}\n\n\t/** Decode one CAB CFDATA LZX frame while preserving the folder's dictionary and Huffman state. */\n\tdecompressFrame(bytes: Uint8Array, outputSize: number): Uint8Array {\n\t\tif (!Number.isInteger(outputSize) || outputSize < 0 || outputSize > FRAME_SIZE) {\n\t\t\tthrow new ArchiveError(`Invalid CAB archive: LZX frame size ${outputSize} exceeds 32768 bytes`);\n\t\t}\n\t\tif (outputSize === 0) return new Uint8Array(0);","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/codecs/lzx.ts#L158-L194","documentation":"The LzxDecoder constructor only supports CAB LZX window sizes from 2^15 (32 KiB) to 2^21 (2 MiB) bits, as used by CAB folders (the cabinet format stores the window bits minus 15 in the folder header). Passing a non-integer or out-of-range windowBits is rejected before any allocation, since the position-slot tables are only defined for 15-21.","triggerScenarios":"new LzxDecoder(14), new LzxDecoder(22), new LzxDecoder(16.5), or new LzxDecoder(NaN) — typically from misreading the CAB folder header's window bits field, which is stored as (windowBits - 15).","commonSituations":"Passing the raw folder-header byte instead of adding 15, feeding LZX streams from other container formats (e.g. MSI/DIET variants) that use different window conventions, typos in configuration.","solutions":["Pass windowBits = rawHeaderValue + 15 when reading a CAB folder header (the stored value is 0-6).","Clamp or validate windowBits to an integer 15-21 before constructing.","If the stream is not CAB LZX, use a decoder for that container's LZX variant instead.","Default to 15 (32 KiB) only when the format genuinely omits the field."],"exampleFix":"// before\nconst decoder = new LzxDecoder(folder.compressionMemory)\n// after\nconst decoder = new LzxDecoder(folder.windowBits + 15) // header stores windowBits - 15 (0..6)","handlingStrategy":"validation","validationCode":"function toWindowBits(storedBits: number): number {\n  const windowBits = storedBits + 15 // CAB folder header stores windowBits - 15\n  if (!Number.isInteger(windowBits) || windowBits < 15 || windowBits > 21) {\n    throw new Error(`Invalid window bits ${storedBits} in CAB folder header`)\n  }\n  return windowBits\n}\nconst decoder = new LzxDecoder(toWindowBits(folder.headerValue))","typeGuard":"function isValidWindowBits(v: unknown): v is number {\n  return typeof v === 'number' && Number.isInteger(v) && v >= 15 && v <= 21\n}","tryCatchPattern":"try {\n  const decoder = new LzxDecoder(folder.windowBits + 15)\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes('window size')) {\n    throw new Error(`Unsupported CAB LZX window bits in folder header: ${folder.windowBits}`)\n  }\n  throw err\n}","preventionTips":["Remember CAB stores windowBits - 15 (values 0-6); add 15 before constructing","Validate the folder header field before instantiating the decoder","Use CAB LZX only for CAB-originated streams; other LZX variants differ"],"tags":["archive","cab","lzx","configuration","validation"],"backgroundTag":"invalid-parameter-value","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}