can1357/oh-my-pi · error · ArchiveError
Invalid ${label} compressed data: match exceeds declared siz
Error message
Invalid ${label} compressed data: match exceeds declared size What it means
A decoded match (back-reference) would write past outSize, the declared uncompressed size. The library refuses to overflow the caller-provided output buffer, which indicates corrupt commands or a wrong outSize.
Source
Thrown at packages/utils/src/ar/lzh.ts:226
let commands: CanonicalHuffman | undefined;
let positions: CanonicalHuffman | undefined;
while (outputPosition < outSize) {
if (blockRemaining === 0) {
blockRemaining = reader.read(16);
if (blockRemaining === 0) throw new ArchiveError(`Invalid ${label} compressed data: empty block`);
const temporary = readTemporaryTree(reader, label);
commands = readCommandTree(reader, temporary, label);
positions = readPositionTree(reader, positionBits, positionSymbols, label);
}
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;
}
View on GitHub (pinned to 9690622007)
Solutions
- Re-read the original-size field from the correct header location (including extended headers)
- Validate the archive source / re-download
- Catch ArchiveError and report the entry as corrupt instead of writing partial output
Example fix
// before const outSize = u64(header, 7); // wrong offset, too small // after const outSize = sizeFromHeader(header); // use parsed real size field
Defensive patterns
Strategy: try-catch
Validate before calling
if (outSize <= 0 || !Number.isSafeInteger(outSize)) throw new Error("invalid declared output size"); Try / catch
try {
const out = decompressLhStatic(packed, outSize, positionBits, positionSymbols, label);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes("match exceeds")) return null;
throw err;
} Prevention
- Read the original-size field from the correct header offset (including extended-header size overrides)
- Verify CRC before extraction
- Never hand-edit archive headers
When it happens
Trigger: decompressLhStatic decodes a command symbol whose implied length (symbol-256+3) exceeds remaining output space — corrupt stream, or outSize computed smaller than the real uncompressed size (e.g. wrong u64 header parse or wrong header field).
Common situations: Header vs actual-data mismatch after editing an archive; wrong original-size field from a damaged extended header; fuzzed inputs.
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/67922675373ebf99.
Report an issue: GitHub.