can1357/oh-my-pi · error · ArchiveError

Corrupt compress (.Z) dictionary code ${code}

Error message

Corrupt compress (.Z) dictionary code ${code}

What it means

While reading LZW codes, each code must reference an existing dictionary entry (code < dictionaryHead). This error means the bitstream contained a code equal to or greater than the number of dictionary entries defined so far — the compressed data is corrupt, truncated mid-stream, or was not produced by the compress algorithm (e.g. raw LZW with different semantics).

Source

Thrown at packages/utils/src/ar/codecs/lzw.ts:134

	const dictionaryLimit = 2 ** maxBits;
	const parents = new Uint16Array(dictionaryLimit);
	const suffixes = new Uint8Array(dictionaryLimit);
	const stack = new Uint8Array(dictionaryLimit);
	const reader = new LsbCodeReader(bytes.subarray(3));
	const output = new BoundedOutput(maxOutput, bytes.byteLength);

	let width = MIN_BITS;
	let dictionaryHead = blockMode ? FIRST_BLOCK_CODE : 256;
	let needsPreviousSuffix = false;

	for (;;) {
		const code = reader.read(width);
		if (code === undefined) {
			reader.assertFinalPadding();
			return output.finish();
		}
		if (code >= dictionaryHead) {
			throw new ArchiveError(`Corrupt compress (.Z) dictionary code ${code}`);
		}
		if (blockMode && code === CLEAR_CODE) {
			reader.alignCodeGroup(width);
			width = MIN_BITS;
			dictionaryHead = FIRST_BLOCK_CODE;
			needsPreviousSuffix = false;
			continue;
		}

		let current = code;
		let stackLength = 0;
		while (current >= 256) {
			if (current >= dictionaryHead || stackLength >= stack.length - 1) {
				throw new ArchiveError("Corrupt compress (.Z) dictionary chain");
			}
			stack[stackLength++] = suffixes[current]!;
			current = parents[current]!;
		}

View on GitHub (pinned to 9690622007)

Solutions

  1. Confirm the buffer starts exactly at the 3-byte header and contains only one .Z stream; split or trim concatenated/extra data.
  2. Re-download/re-extract the file and verify integrity (cksum, md5) — this error almost always means corrupt or truncated payload.
  3. Verify the data is ncompress-format LZW, not GIF/TIFF LZW; use a codec matching the actual format.
  4. If decoding concatenated members, call lzwDecompress per member instead of once over the joined bytes.

Example fix

// before
const all = Buffer.concat([z1, z2]);
await lzwDecompress(all, limit); // throws: corrupt dictionary code
// after
const out1 = await lzwDecompress(z1, limit);
const out2 = await lzwDecompress(z2, limit);
Defensive patterns

Strategy: try-catch

Validate before calling

if (!isCompressZ(bytes)) throw new Error("not .Z");
// one stream per call — do not concatenate multiple .Z members

Try / catch

try {
  return await lzwDecompress(bytes, maxOutput);
} catch (e) {
  if (e instanceof ArchiveError && e.message.includes("Corrupt compress (.Z) dictionary code")) {
    throw new Error(".Z payload corrupt, truncated, or contains multiple concatenated streams");
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling lzwDecompress on a stream whose code stream references codes at or beyond the current dictionary position: bit-shifted data (e.g. a byte inserted/removed after the 3-byte header), a non-block-mode stream fed where codes were written differently, truncated file decoded anyway, or plain-LZW (GIF/TIFF-style) data misidentified as .Z.

Common situations: Concatenated .Z files (each has its own header) being decoded as one stream; off-by-one slicing after stripping the header; corrupted disk/transfer data; attempting to decode .Z output of 'compress -C' variants with different bit-packing.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/624df308736596fd. Report an issue: GitHub.