can1357/oh-my-pi · error · ArchiveError
Truncated compress (.Z) code group
Error message
Truncated compress (.Z) code group
What it means
compress (.Z) codes are read in groups whose width starts at 9 bits and grows as the code table expands; alignCodeGroup snaps the bit position to the next width-byte boundary. This error is thrown when the computed group boundary lies beyond the end of the input, meaning the stream was cut off before the current code group completed.
Source
Thrown at packages/utils/src/ar/codecs/lzw.ts:38
read(width: number): number | undefined {
if (this.remainingBits < width) {
return undefined;
}
let value = 0;
for (let bit = 0; bit < width; bit++) {
const position = this.#bitPosition + bit;
value += ((this.#bytes[position >>> 3]! >>> (position & 7)) & 1) * 2 ** bit;
}
this.#bitPosition += width;
return value;
}
alignCodeGroup(width: number): void {
const groupBits = width * 8;
const aligned = this.#groupStart + Math.ceil((this.#bitPosition - this.#groupStart) / groupBits) * groupBits;
if (aligned > this.#bytes.byteLength * 8) {
throw new ArchiveError("Truncated compress (.Z) code group");
}
this.#bitPosition = aligned;
this.#groupStart = aligned;
}
assertFinalPadding(): void {
this.#assertZeroBits(this.#bytes.byteLength * 8);
}
#assertZeroBits(end: number): void {
for (let position = this.#bitPosition; position < end; position++) {
if (((this.#bytes[position >>> 3]! >>> (position & 7)) & 1) !== 0) {
throw new ArchiveError("Invalid non-zero compress (.Z) padding");
}
}
}
}
View on GitHub (pinned to 9690622007)
Solutions
- Re-download/re-copy the .Z file and verify its size (e.g. with `compress -c | wc -c` comparison or `zcat` test).
- Check the code that reads the file — ensure it reads the full file (use Bun.file().bytes() / complete readFile) rather than a partial buffer.
- Test the file with `zcat file.Z > /dev/null` to confirm it decompresses outside this library.
- If concatenating .Z members, split on member boundaries instead of appending raw compressed bytes.
Example fix
// before: partial read const bytes = buf.subarray(0, 512); lzwDecompress(bytes, max); // after: full file const bytes = new Uint8Array(await Bun.file(path).arrayBuffer()); lzwDecompress(bytes, max);
Defensive patterns
Strategy: validation
Validate before calling
if (bytes.byteLength < 3 || bytes[0] !== 0x1f || bytes[1] !== 0x9d) throw new Error("Not a compress (.Z) stream"); Try / catch
try {
return lzwDecompress(bytes, maxOutput);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes("code group")) {
throw new Error(".Z stream is truncated (ends mid code group) — re-obtain the file", { cause: err });
}
throw err;
} Prevention
- Verify the .Z magic (0x1F 0x9D) and full file size before decoding.
- Cross-check with `zcat file.Z > /dev/null` when a file from an external source fails.
- Read files completely — avoid fixed-size partial reads.
- Treat as fatal corruption; retrying decode on the same bytes will not help.
When it happens
Trigger: Calling alignCodeGroup (during decode/lzwDecompress) when the remaining input bits are fewer than needed to reach the next width-aligned boundary — i.e. the input ends mid-group.
Common situations: Truncated .Z file from an incomplete download or interrupted transfer; reading fewer bytes than the compressed stream requires; corrupted archive tail.
Related errors
- Truncated compress (.Z) header
- Invalid non-zero compress (.Z) padding
- Compress (.Z) output exceeds the ${this.#limit}-byte limit
- Invalid LZMA2 chunk size
- Invalid compress (.Z) output limit
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/d517b474a7aa87e2.
Report an issue: GitHub.