{"record":{"id":"f7eb14392083e079","repo":"can1357/oh-my-pi","slug":"invalid-cab-archive-lzx-match-offset-exceeds-avai","errorCode":null,"errorMessage":"Invalid CAB archive: LZX match offset exceeds available history","messagePattern":"Invalid CAB archive: LZX match offset exceeds available history","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/codecs/lzx.ts","lineNumber":318,"sourceCode":"\t\t\t} else {\n\t\t\t\tif (slot >= this.#positionBase.byteLength)\n\t\t\t\t\tthrow new ArchiveError(\"Invalid CAB archive: LZX position slot is out of range\");\n\t\t\t\tconst extra = this.#extraBits[slot]!;\n\t\t\t\tmatchOffset = this.#positionBase[slot]! - 2;\n\t\t\t\tif (this.#blockType === 2 && extra >= 3) {\n\t\t\t\t\tif (extra > 3) matchOffset += reader.readBits(extra - 3) * 8;\n\t\t\t\t\tif (!this.#alignedTable) throw new ArchiveError(\"Invalid CAB archive: missing LZX aligned tree\");\n\t\t\t\t\tmatchOffset += this.#alignedTable.decode(reader);\n\t\t\t\t} else if (extra !== 0) {\n\t\t\t\t\tmatchOffset += reader.readBits(extra);\n\t\t\t\t}\n\t\t\t\tthis.#r2 = this.#r1;\n\t\t\t\tthis.#r1 = this.#r0;\n\t\t\t\tthis.#r0 = matchOffset;\n\t\t\t}\n\n\t\t\tif (matchOffset <= 0 || matchOffset > Math.min(this.#decodedSize, this.#window.byteLength)) {\n\t\t\t\tthrow new ArchiveError(\"Invalid CAB archive: LZX match offset exceeds available history\");\n\t\t\t}\n\t\t\tfor (let index = 0; index < matchLength; index++) {\n\t\t\t\tconst source = (this.#windowPosition - matchOffset + this.#window.byteLength) % this.#window.byteLength;\n\t\t\t\tthis.#writeByte(this.#window[source]!, output, outputStart + produced + index);\n\t\t\t}\n\t\t\tproduced += matchLength;\n\t\t}\n\t\treturn produced;\n\t}\n\n\t#writeByte(value: number, output: Uint8Array, outputPosition: number): void {\n\t\toutput[outputPosition] = value;\n\t\tthis.#window[this.#windowPosition] = value;\n\t\tthis.#windowPosition = (this.#windowPosition + 1) % this.#window.byteLength;\n\t\tthis.#decodedSize++;\n\t}\n\n\t#translateE8(raw: Uint8Array): Uint8Array {","sourceCodeStart":300,"sourceCodeEnd":336,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/codecs/lzx.ts#L300-L336","documentation":"The decoded match offset is zero or larger than the bytes decoded so far / window size, so the copy would read before the start of the output history. This is a definitive corruption signal in the LZX bitstream.","triggerScenarios":"decompressFrame -> #decodeRun resolves a matchOffset <= 0 or > min(decodedSize, window.byteLength) before copying matchLength bytes from the ring window.","commonSituations":"Truncated or corrupted CAB extraction, wrong start offset into compressed data, fuzzed inputs.","solutions":["Re-obtain the CAB from a trusted source.","Confirm you decompress frames in order from the first frame; LZX history depends on all prior output.","Catch ArchiveError and report the file as corrupt."],"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(\"exceeds available history\")) {\n    // corrupt back-reference — abort and report\n  } else throw err;\n}","preventionTips":["Decompress frames strictly in order so history is complete","Reject archives failing checksum verification","Treat any ArchiveError during LZX decode as terminal"],"tags":["archive","cab","lzx","corrupt-data"],"backgroundTag":"corrupt-archive-data","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}