{"record":{"id":"5890db64a27d219b","repo":"can1357/oh-my-pi","slug":"invalid-cab-archive-missing-lzx-decode-trees","errorCode":null,"errorMessage":"Invalid CAB archive: missing LZX decode trees","messagePattern":"Invalid CAB archive: missing LZX decode trees","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/codecs/lzx.ts","lineNumber":269,"sourceCode":"\t\t\tthis.#r0 = reader.readUInt32LE();\n\t\t\tthis.#r1 = reader.readUInt32LE();\n\t\t\tthis.#r2 = reader.readUInt32LE();\n\t\t\tif (this.#r0 === 0 || this.#r1 === 0 || this.#r2 === 0) {\n\t\t\t\tthrow new ArchiveError(\"Invalid CAB archive: invalid LZX repeated offset\");\n\t\t\t}\n\t\t\tthis.#uncompressedPadding = (this.#blockLength & 1) !== 0;\n\t\t\treturn;\n\t\t}\n\t\tthrow new ArchiveError(`Invalid CAB archive: unsupported LZX block type ${this.#blockType}`);\n\t}\n\n\t#decodeRun(reader: LzxBitReader, output: Uint8Array, outputStart: number, count: number): number {\n\t\tif (this.#blockType === 3) {\n\t\t\tfor (let index = 0; index < count; index++) this.#writeByte(reader.readByte(), output, outputStart + index);\n\t\t\treturn count;\n\t\t}\n\t\tif (!this.#mainTable || !this.#lengthTable)\n\t\t\tthrow new ArchiveError(\"Invalid CAB archive: missing LZX decode trees\");\n\n\t\tlet produced = 0;\n\t\twhile (produced < count) {\n\t\t\tconst element = this.#mainTable.decode(reader);\n\t\t\tif (element < 256) {\n\t\t\t\tthis.#writeByte(element, output, outputStart + produced);\n\t\t\t\tproduced++;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst match = element - 256;\n\t\t\tlet matchLength = match & NUM_PRIMARY_LENGTHS;\n\t\t\tif (matchLength === NUM_PRIMARY_LENGTHS) matchLength += this.#lengthTable.decode(reader);\n\t\t\tmatchLength += MIN_MATCH;\n\t\t\tif (matchLength > count - produced || matchLength > this.#blockRemaining - produced) {\n\t\t\t\tthrow new ArchiveError(\"Invalid CAB archive: LZX match crosses a frame or block boundary\");\n\t\t\t}\n","sourceCodeStart":251,"sourceCodeEnd":287,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/codecs/lzx.ts#L251-L287","documentation":"#decodeRun tries to Huffman-decode symbols but the main and length decode trees were never built (a Verbatim/Aligned block header was not parsed for this block). This indicates internal state misuse or a corrupt stream where block setup was skipped.","triggerScenarios":"decompressFrame -> #decodeRun called with blockType 1 or 2 while #mainTable or #lengthTable is null (trees not initialized via #readBlockHeader).","commonSituations":"A CAB payload whose block header parsing diverged earlier (bad block type/length) leaving trees unset; calling low-level decode APIs out of order.","solutions":["Ensure decompressFrame is used end-to-end rather than invoking internal decode pieces directly.","Validate the archive; if the header parsed but trees are missing, the stream is corrupt.","Re-obtain the archive from a trusted source."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const out = decompressFrame(frame);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes(\"missing LZX decode trees\")) {\n    // stream state desync — mark archive corrupt\n  } else throw err;\n}","preventionTips":["Use only the public decompressFrame API, not internal decode helpers","Decompress complete frames; never skip block headers","Validate archive integrity before decoding"],"tags":["archive","cab","lzx","state-error"],"backgroundTag":"corrupt-archive-data","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}