can1357/oh-my-pi · error · ArchiveError
Invalid ${label} position Huffman table size
Error message
Invalid ${label} position Huffman table size What it means
readPositionTree reads the count of encoded position symbols; if that count exceeds the position symbol space (positionSymbols), the table cannot be valid. This guards against corrupt bits or wrong positionBits/symbolCount parameters.
Source
Thrown at packages/utils/src/ar/lzh.ts:189
const skipped = code === 0 ? 1 : code === 1 ? reader.read(4) + 3 : reader.read(9) + 20;
if (index + skipped > encodedCount) throw new ArchiveError(`Invalid ${label} command Huffman table`);
index += skipped;
} else {
lengths[index++] = code - 2;
}
}
return CanonicalHuffman.build(lengths, symbolCount, label);
}
function readPositionTree(
reader: MsbBitReader,
positionBits: number,
symbolCount: number,
label: string,
): CanonicalHuffman {
const encodedCount = reader.read(positionBits);
if (encodedCount === 0) return CanonicalHuffman.single(reader.read(positionBits), symbolCount, label);
if (encodedCount > symbolCount) throw new ArchiveError(`Invalid ${label} position Huffman table size`);
const lengths = new Uint8Array(symbolCount);
for (let index = 0; index < encodedCount; index++) lengths[index] = readCodeLength(reader, label);
return CanonicalHuffman.build(lengths, symbolCount, label);
}
/** @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;View on GitHub (pinned to 9690622007)
Solutions
- Pass the correct positionBits/positionSymbols for the method being decoded (e.g. larger table for -lh6-/-lh7-)
- Re-extract or validate the archive source; check CRC
- Verify the bit reader starts at the true start of the compressed stream
- Handle ArchiveError for untrusted inputs
Example fix
// before decompressLhStatic(packed, outSize, 5, 256, "LZH -lh5-"); // data is actually -lh7- // after // -lh7- uses 20-bit positions / larger symbol table decompressLhStatic(packed, outSize, 20, 1024, "LZH -lh7-");
Defensive patterns
Strategy: validation
Validate before calling
// positionSymbols must be large enough for the method's positionBits
if (2 ** positionBits > positionSymbols) throw new Error("position table parameters inconsistent for this method"); Try / catch
try {
const out = decompressLhStatic(packed, outSize, positionBits, positionSymbols, label);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes("position Huffman")) return null;
throw err;
} Prevention
- Use the correct parameter set per method (-lh4-/-lh5-/-lh6-/-lh7-/ARJ 1-3)
- Validate archive checksums before decompressing
- Never reuse hardcoded parameters across archive variants
When it happens
Trigger: decompressLhStatic on data whose position-table symbol count field (read with positionBits bits) yields a value greater than positionSymbols — corrupt stream, or positionBits/positionSymbols mismatched with the actual method (e.g. -lh5- vs -lh7- tables).
Common situations: Decoding -lh7-/ARJ method 3 data with -lh5- parameters (positionSymbols too small); bitmisalignment after a bad command table; 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/13b866c5755c0103.
Report an issue: GitHub.