can1357/oh-my-pi · error · ArchiveError

Invalid compress (.Z) maximum code width ${maxBits}

Error message

Invalid compress (.Z) maximum code width ${maxBits}

What it means

The low 5 bits of the .Z flags byte encode the maximum LZW code width, which must be between 9 (MIN_BITS) and 16 (MAX_BITS) bits for this decoder. This error means the header declares a code width outside that range, so the stream is not a valid compress stream this library can decode.

Source

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

function decode(bytes: Uint8Array, maxOutput: number): Uint8Array {
	if (!Number.isSafeInteger(maxOutput) || maxOutput < 0) {
		throw new ArchiveError("Invalid compress (.Z) output limit");
	}
	if (bytes.byteLength < 3) {
		throw new ArchiveError("Truncated compress (.Z) header");
	}
	if (bytes[0] !== 0x1f || bytes[1] !== 0x9d) {
		throw new ArchiveError("Invalid compress (.Z) header");
	}

	const flags = bytes[2]!;
	if ((flags & 0x60) !== 0) {
		throw new ArchiveError("Unsupported compress (.Z) header flags");
	}
	const maxBits = flags & 0x1f;
	if (maxBits < MIN_BITS || maxBits > MAX_BITS) {
		throw new ArchiveError(`Invalid compress (.Z) maximum code width ${maxBits}`);
	}
	const blockMode = (flags & 0x80) !== 0;
	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();

View on GitHub (pinned to 9690622007)

Solutions

  1. Verify the flags byte: a valid ncompress file typically has bytes[2] in 0x88-0x9f (block mode, 9-16 max bits); a value like 0x80 means width 0 and is corrupt.
  2. Re-acquire the archive and validate with `compress -d` or `file` before decoding.
  3. If the data uses a nonstandard LZW width, decode it with a dedicated LZW library rather than this .Z decoder.
  4. Check the code path did not overwrite/shift the header bytes before calling (e.g. wrong slice offset).

Example fix

// before
await lzwDecompress(bytes, maxOutput);
// after
const maxBits = (bytes[2] ?? 0) & 0x1f;
if (maxBits < 9 || maxBits > 16) {
  throw new Error(`corrupt .Z header: max code width ${maxBits}`);
}
await lzwDecompress(bytes, maxOutput);
Defensive patterns

Strategy: validation

Validate before calling

const maxBits = (bytes[2] ?? 0) & 0x1f;
if (maxBits < 9 || maxBits > 16) throw new Error(`Corrupt .Z header: max code width ${maxBits} not in [9,16]`);

Type guard

function hasValidZMaxBits(bytes: Uint8Array): boolean {
  if (bytes.byteLength < 3) return false;
  const maxBits = bytes[2]! & 0x1f;
  return maxBits >= 9 && maxBits <= 16;
}

Try / catch

try {
  return await lzwDecompress(bytes, maxOutput);
} catch (e) {
  if (e instanceof ArchiveError && e.message.includes("maximum code width")) {
    throw new Error(".Z header declares an impossible code width — file is corrupt");
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling lzwDecompress on a stream where (bytes[2] & 0x1f) is < 9 or > 16 — typically because the flags byte is corrupt (e.g. 0x00), the file is not really a .Z stream despite matching magic, or a hypothetical >16-bit compressor produced it.

Common situations: Header corruption from a bad transfer or truncated/partial file where the third byte was zeroed; archives created with nonstandard LZW variants using different bit widths; fuzzed or adversarial inputs.

Related errors


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