can1357/oh-my-pi · error · ArchiveError
Invalid compress (.Z) header
Error message
Invalid compress (.Z) header
What it means
lzwDecompress() only decodes ncompress-style Unix compress (.Z) streams, which must begin with the two magic bytes 0x1f 0x9d followed by a flags byte. This error means the input does not start with that magic signature, so the bytes are not a .Z stream at all (or the first two bytes were lost/corrupted in transit).
Source
Thrown at packages/utils/src/ar/codecs/lzw.ts:104
let capacity = Math.max(needed, Math.min(this.#limit, Math.max(64, this.#bytes.byteLength * 2)));
if (capacity > this.#limit) {
capacity = this.#limit;
}
const grown = new Uint8Array(capacity);
grown.set(this.#bytes.subarray(0, this.#length));
this.#bytes = grown;
}
}
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);
View on GitHub (pinned to 9690622007)
Solutions
- Call isCompressZ(bytes) first and reject/handle non-matching input instead of decompressing blindly.
- Verify the file is actually a compress (.Z) file (file(1) or first bytes 1f 9d); if it is gzip/zlib/deflate, use the matching codec instead.
- Check that the buffer passed starts at offset 0 of the stream — no leading metadata or partial read that skipped the header.
- Re-download or re-extract the file if the header bytes are corrupt (corruption during transfer).
Example fix
// before
const out = await lzwDecompress(data, 10_000_000);
// after
import { isCompressZ, lzwDecompress } from "@oh-my-pi/pi-utils";
if (!isCompressZ(data)) throw new Error("not a .Z stream");
const out = await lzwDecompress(data, 10_000_000); Defensive patterns
Strategy: validation
Validate before calling
import { isCompressZ } from "@oh-my-pi/pi-utils";
if (!isCompressZ(bytes)) throw new Error("Input is not a compress (.Z) stream: expected magic 0x1f 0x9d"); Type guard
function isCompressZStream(bytes: Uint8Array): boolean {
return bytes.byteLength >= 3 && bytes[0] === 0x1f && bytes[1] === 0x9d;
} Try / catch
try {
const out = await lzwDecompress(bytes, maxOutput);
} catch (e) {
if (e instanceof ArchiveError && e.message.includes("Invalid compress (.Z) header")) {
throw new Error("File is not a .Z archive — check format/extension");
}
throw e;
} Prevention
- Always sniff the magic with isCompressZ() before dispatching to the .Z codec.
- Route by actual format, not file extension — .Z extensions can be mislabeled gzip or raw data.
- Preserve the original stream bytes end-to-end; avoid text-mode transfers that mangle headers.
When it happens
Trigger: Calling lzwDecompress(bytes, maxOutput) with a Uint8Array whose bytes[0] !== 0x1f or bytes[1] !== 0x9d — e.g. passing a gzip (0x1f 0x8b), zlib (0x78), bzip2 ('BZ'), or raw LZW stream, or a .Z file whose header bytes were stripped by an upload/transfer step.
Common situations: Handing the function a file with a renamed .Z extension that is actually another format; concatenating or re-assembling archive members and off-by-one slicing away the 3-byte header; base64/text-mode transfers corrupting the first bytes; trying to decompress an already-uncompressed payload.
Related errors
- Invalid compress (.Z) maximum code width ${maxBits}
- Truncated compress (.Z) code group
- Invalid non-zero compress (.Z) padding
- Compress (.Z) output exceeds the ${this.#limit}-byte limit
- Invalid compress (.Z) output limit
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/35342b964e5cc94b.
Report an issue: GitHub.