can1357/oh-my-pi · error · ArchiveError
Invalid ${label} compressed data: block exceeds declared siz
Error message
Invalid ${label} compressed data: block exceeds declared size What it means
After the loop finishes (output full), a nonzero blockRemaining means the declared command count for the block was not fully consumed — the block claims more commands than the output size accounts for. The library treats this as corrupt data rather than silently accepting trailing references.
Source
Thrown at packages/utils/src/ar/lzh.ts:240
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");
output[outputPosition++] = value;
history[historyPosition] = value;
historyPosition = (historyPosition + 1) & 2047;
};
while (outputPosition < outSize) {View on GitHub (pinned to 9690622007)
Solutions
- Verify the original-size header field (including extended-header overrides)
- Check archive integrity (CRC) and re-obtain the file
- Treat the entry as corrupt: catch ArchiveError and skip/report
Defensive patterns
Strategy: try-catch
Validate before calling
if (!Number.isSafeInteger(outSize) || outSize <= 0) throw new Error("outSize must be a positive safe integer"); Try / catch
try {
const out = decompressLhStatic(packed, outSize, positionBits, positionSymbols, label);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes("block exceeds")) reportCorrupt(entry);
else throw err;
} Prevention
- Ensure outSize comes from the authoritative size field (incl. extended headers)
- Check CRC after decompression to detect silent mismatch
- Re-extract from a verified copy on failure
When it happens
Trigger: decompressLhStatic fills outSize exactly but the current block's 16-bit command counter is still nonzero — corrupt header count, wrong outSize (too small), or overlapping/malformed blocks.
Common situations: Archives whose original-size field was edited or damaged; streams where an earlier corrupt table caused misdecoding; 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/c38d5d57a22f9cea.
Report an issue: GitHub.