can1357/oh-my-pi · error · ArchiveError
Invalid ${label} compressed data: history distance is out of
Error message
Invalid ${label} compressed data: history distance is out of range What it means
A match's distance (back-reference offset) must be smaller than both the dictionary size and the bytes already emitted; otherwise it would read before the start of the output. This indicates corrupt position data.
Source
Thrown at packages/utils/src/ar/lzh.ts:235
}
blockRemaining--;
const symbol = commands!.decode(reader);
if (symbol < 256) {
output[outputPosition++] = symbol;
continue;
}
const length = symbol - 256 + 3;
if (length > outSize - outputPosition) {
throw new ArchiveError(`Invalid ${label} compressed data: match exceeds declared size`);
}
const positionCode = positions!.decode(reader);
let distance = positionCode;
if (positionCode > 1) {
const lowBitCount = positionCode - 1;
distance = 2 ** lowBitCount + reader.read(lowBitCount);
}
if (distance >= dictionarySize || distance >= outputPosition) {
throw new ArchiveError(`Invalid ${label} compressed data: history distance is out of range`);
}
let sourcePosition = outputPosition - distance - 1;
for (let index = 0; index < length; index++) output[outputPosition++] = output[sourcePosition++]!;
}
if (blockRemaining !== 0) throw new ArchiveError(`Invalid ${label} compressed data: block exceeds declared size`);
reader.assertZeroPadding();
return output;
}
function decompressLzs(packed: Uint8Array, outSize: number): Uint8Array {
const reader = new MsbBitReader(packed, "LZH -lzs-");
const output = new Uint8Array(outSize);
const history = new Uint8Array(2048);
history.fill(0x20);
let historyPosition = 2048 - 17;
let outputPosition = 0;
const emit = (value: number): void => {
if (outputPosition >= outSize) throw new ArchiveError("Invalid LZH -lzs- data: output exceeds declared size");View on GitHub (pinned to 9690622007)
Solutions
- Pass the correct dictionarySize for the method variant
- Ensure decompression starts at the true beginning of the member's compressed data
- Re-validate/re-download the archive
- Catch ArchiveError for untrusted input
Example fix
// before decompressLhStatic(packed, outSize, 5, 256, "LZH -lh5-"); // dictionary 4KB // after // -lh6-/-lh7- use larger dictionaries decompressLhStatic(packed, outSize, 6, 8192, "LZH -lh6-");
Defensive patterns
Strategy: try-catch
Validate before calling
// dictionarySize must match the method; check it is a power-of-two-ish sane value
if (dictionarySize <= 0 || !Number.isSafeInteger(dictionarySize)) throw new Error("bad dictionary size"); Try / catch
try {
const out = decompressLhStatic(packed, outSize, positionBits, positionSymbols, label);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes("distance")) return null;
throw err;
} Prevention
- Match dictionarySize to the method variant (-lh5- 4KB, -lh6- 32KB, -lh7- 64KB)
- Decompress from the member's true stream start
- Validate archive integrity first
When it happens
Trigger: decompressLhStatic decodes a position symbol plus low bits whose distance >= dictionarySize or >= bytes written so far — corrupt stream, wrong dictionarySize for the method, or output starting mid-stream so outputPosition is too small for early references.
Common situations: Wrong dictionary size parameter (e.g. 4KB for -lh5- data that needs larger); misparsed extended headers shifting stream start; fuzzed archives.
Related errors
- Invalid ${label} Huffman table: oversubscribed codes
- Invalid ${label} Huffman table: incomplete codes
- Invalid ${label} Huffman table: prefix collision
- Invalid ${label} Huffman table: duplicate code
- Invalid ${this.#label} Huffman code
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/44c1deea1f3f651d.
Report an issue: GitHub.