can1357/oh-my-pi · error · ArchiveError
Unsupported RAR4 PPMd compressed block
Error message
Unsupported RAR4 PPMd compressed block
What it means
readTables in the RAR4 decoder reads a block-type bit from the compressed stream: a 1 indicates a PPMd (PPM version with variant H) compressed block. The decoder only implements the LZSS+Huffman path, so PPMd blocks are rejected with this error rather than producing garbage output.
Source
Thrown at packages/utils/src/ar/rar/rar4-decoder.ts:176
const prior =
this.#history.byteLength > dictionarySize
? this.#history.subarray(this.#history.byteLength - dictionarySize)
: this.#history;
const output = new Uint8Array(prior.byteLength + unpackedSize + 260);
output.set(prior);
const outputStart = prior.byteLength;
const outputEnd = outputStart + unpackedSize;
let outputPosition = outputStart;
const bits = new Bits(packed);
const main = new Huffman(MAIN_SIZE);
const distanceDecoder = new Huffman(DIST_SIZE);
const lowDistanceDecoder = new Huffman(LOW_DIST_SIZE);
const lengthDecoder = new Huffman(LEN_SIZE);
const filters: PendingFilter[] = [];
const readTables = (): void => {
bits.align();
if (bits.read(1) !== 0) throw new ArchiveError("Unsupported RAR4 PPMd compressed block");
const keepPrevious = bits.read(1) !== 0;
this.#previousLowDistance = 0;
this.#lowDistanceRepeats = 0;
if (!keepPrevious) this.#carriedLengths.fill(0);
const lengths = readLengthTable(bits, this.#carriedLengths, TOTAL_SIZE);
let offset = 0;
main.build(lengths, offset, MAIN_SIZE);
offset += MAIN_SIZE;
distanceDecoder.build(lengths, offset, DIST_SIZE);
offset += DIST_SIZE;
lowDistanceDecoder.build(lengths, offset, LOW_DIST_SIZE);
offset += LOW_DIST_SIZE;
lengthDecoder.build(lengths, offset, LEN_SIZE);
this.#carriedLengths.set(lengths);
};
const copyMatch = (distance: number, length: number): void => {
if (distance <= 0 || distance > dictionarySize || distance > outputPosition) corrupt("invalid LZ distance");View on GitHub (pinned to 9690622007)
Solutions
- Repack the archive using standard LZ compression in WinRAR/7-Zip (avoid the PPMd option), then retry.
- Extract with a full-featured tool (7-Zip, unrar) that supports PPMd and feed the unpacked files to this library.
- Detect the RAR compression method up front and warn/fallback for PPMd members instead of failing mid-extract.
- If the flag bit appears in an implausible position, suspect corruption — validate the archive with an external tool.
Example fix
// before
await extractArchive("text-heavy.ppmd.rar", dest);
// after (shell pre-conversion)
7z x text-heavy.ppmd.rar -otmp && 7z a -mx=9 text-heavy.lz.zip ./tmp/* Defensive patterns
Strategy: fallback
Validate before calling
// Inspect the RAR main/file header compression method; PPMd is method 3-5 with the PPMd flag. // If a member uses PPMd, route it to an external extractor instead of this decoder. const usesPpmd = detectRarCompressionMethod(p) === "ppmd"; if (usesPpmd) return extractWithExternalTool(p, dest);
Try / catch
try {
await extractArchive(p, dest);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes("PPMd")) {
return extractWith7zip(p, dest); // fallback decoder
}
throw err;
} Prevention
- Repack RAR archives with standard LZ compression (not PPMd) before automated processing.
- Keep a full-featured fallback extractor (7z/unrar) available for exotic compression methods.
- Pre-scan member compression methods and warn before attempting extraction.
- Normalize incoming archives to zip/tar in ingestion pipelines.
When it happens
Trigger: Decoding a RAR4 file whose archive creator selected PPMd compression (RAR 3.x 'ppmd' method, -mcppmd or compression method 3–5 with PPMd) and the decoder reaches the block-table reader and sees the PPMd flag bit set.
Common situations: Archives compressed with WinRAR's PPMd option; archives where large text payloads were stored with PPMd for better ratios; extracting only some members works (LZ ones) while PPMd ones fail.
Related errors
- Unsupported RAR4 compression algorithm version ${version}
- Unsupported RAR4 RarVM filter type ${type || "unknown"}
- Invalid RAR4 archive: ${reason}
- Unsupported deb tar compression in '${outerEntry.path}'
- LZH member '${memberPath}' uses unsupported dynamic-Huffman
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/21da78e671aa768d.
Report an issue: GitHub.