can1357/oh-my-pi · error · ArchiveError
Invalid ${label} compressed data: empty block
Error message
Invalid ${label} compressed data: empty block What it means
Each Huffman block begins with a 16-bit command count. A zero count is invalid because decompression still needs to fill the output; the library throws rather than looping forever.
Source
Thrown at packages/utils/src/ar/lzh.ts:213
/** @internal Decode the static-Huffman LZSS stream shared by LZH and ARJ methods 1-3. */
export function decompressLhStatic(
packed: Uint8Array,
outSize: number,
dictionarySize: number,
positionBits: number,
positionSymbols: number,
label: string,
): Uint8Array {
const reader = new MsbBitReader(packed, label);
const output = new Uint8Array(outSize);
let outputPosition = 0;
let blockRemaining = 0;
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;View on GitHub (pinned to 9690622007)
Solutions
- Verify the compressed-data start offset (extended headers parsed/skipped correctly)
- Re-obtain the archive and check CRC
- Confirm the method variant is supported before decompressing
- Catch ArchiveError for untrusted input
Example fix
// before const data = packed.slice(headerSize); // forgot to skip extended headers // after const data = packed.slice(headerSize + extendedHeaderBytes);
Defensive patterns
Strategy: try-catch
Validate before calling
if (packed.length < 2) throw new Error("compressed member too short to contain a block header"); Try / catch
try {
const out = decompressLhStatic(packed, outSize, positionBits, positionSymbols, label);
} catch (err) {
if (err instanceof ArchiveError) reportCorruptEntry(entryName, err.message);
else throw err;
} Prevention
- Parse all extended headers before computing the data start offset
- Check archive-level CRC/integrity first
- Treat every external archive as untrusted input
When it happens
Trigger: decompressLhStatic reads a block whose 16-bit blockRemaining header is 0 — corrupt data, zero-filled region, or reader positioned at the wrong offset (e.g. wrong extended-header skip before data start).
Common situations: Truncated archives padded with zeros; incorrect handling of -lh4- vs -lh5- header differences causing offset drift; 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/8e3e81e0104b07cf.
Report an issue: GitHub.