can1357/oh-my-pi · error · ArchiveError
Invalid non-zero compress (.Z) padding
Error message
Invalid non-zero compress (.Z) padding
What it means
After the compress (.Z) end-of-stream code, the remaining bits up to the final byte boundary must be zero padding. #assertZeroBits scans each leftover bit and throws if any is non-zero. Non-zero padding means the stream did not terminate where it claims, so the input is malformed or there is extra data.
Source
Thrown at packages/utils/src/ar/codecs/lzw.ts:51
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");
}
}
}
}
class BoundedOutput {
readonly #limit: number;
#bytes: Uint8Array;
#length = 0;
constructor(limit: number, inputSize: number) {
this.#limit = limit;
this.#bytes = new Uint8Array(Math.min(limit, Math.max(64, Math.min(inputSize * 2, 64 * 1024))));
}
appendReversed(stack: Uint8Array, length: number): void {
this.#ensure(length);
for (let index = length - 1; index >= 0; index--) {View on GitHub (pinned to 9690622007)
Solutions
- Split concatenated .Z members and decode each independently (the compress format supports concatenated members).
- Strip any known trailing metadata/garbage before decompressing.
- Verify file integrity with `zcat` / checksum comparison.
- Ensure the buffer passed covers exactly the compressed stream, not extra trailing bytes.
Example fix
// before: one call on concatenation lzwDecompress(concatBytes, max); // after: decode each .Z member for (const member of splitZMembers(concatBytes)) lzwDecompress(member, max);
Defensive patterns
Strategy: try-catch
Try / catch
try {
return lzwDecompress(bytes, maxOutput);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes("padding")) {
throw new Error("Non-zero bits after .Z EOF code — likely concatenated members or trailing garbage", { cause: err });
}
throw err;
} Prevention
- Split concatenated .Z members and decode each separately.
- Strip known trailing metadata before decompressing.
- Verify checksums so single-bit tail corruption is caught early.
- Pass exactly the compressed stream bytes, no extra tail.
When it happens
Trigger: Calling lzwDecompress (via assertFinalPadding) on input where bits following the EOF code are set — e.g. a second concatenated .Z member, appended garbage, or corruption in the final byte.
Common situations: Concatenated .Z archives decoded as a single stream; trailing junk after decompressed data; single-bit corruption in the last byte; hand-trimmed buffers that cut into the final code word.
Related errors
- Truncated compress (.Z) code group
- Compress (.Z) output exceeds the ${this.#limit}-byte limit
- Truncated compress (.Z) header
- Invalid LZMA2 stream: trailing data
- Invalid LZMA2 stream: ${error instanceof Error ? error.messa
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/c42c5a0d7625675e.
Report an issue: GitHub.