can1357/oh-my-pi · error · ArchiveError
Compress (.Z) output exceeds the ${this.#limit}-byte limit
Error message
Compress (.Z) output exceeds the ${this.#limit}-byte limit What it means
BoundedOutput caps decompressed output at a caller-supplied limit to prevent zip-bomb style memory exhaustion. #ensure throws when writing `additional` bytes would push the total past that limit (or overflow a safe integer). The limit is defensive, not a stream property — the input may be valid but simply decompresses larger than allowed.
Source
Thrown at packages/utils/src/ar/codecs/lzw.ts:81
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--) {
this.#bytes[this.#length++] = stack[index]!;
}
}
finish(): Uint8Array {
return this.#bytes.slice(0, this.#length);
}
#ensure(additional: number): void {
const needed = this.#length + additional;
if (!Number.isSafeInteger(needed) || needed > this.#limit) {
throw new ArchiveError(`Compress (.Z) output exceeds the ${this.#limit}-byte limit`);
}
if (needed <= this.#bytes.byteLength) {
return;
}
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");
}View on GitHub (pinned to 9690622007)
Solutions
- Raise maxOutput to a value ≥ the true decompressed size (known file size, or a generous upper bound).
- If the source is untrusted, keep a limit but stream/process in chunks instead of removing the cap entirely.
- Confirm you aren't passing the compressed size as the output limit.
- If the data is untrusted and limit removal is unacceptable, treat the error as a decompression-bomb signal and reject the input.
Example fix
// before lzwDecompress(bytes, bytes.byteLength); // after: output can be larger than input; use a real bound lzwDecompress(bytes, 256 * 1024 * 1024);
Defensive patterns
Strategy: validation
Validate before calling
// Know the decompressed size before decoding, or pick a generous bound
const maxOutput = knownUncompressedSize ?? 256 * 1024 * 1024;
if (!Number.isSafeInteger(maxOutput) || maxOutput < 0) throw new Error("Invalid maxOutput"); Try / catch
try {
return lzwDecompress(bytes, maxOutput);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes("-byte limit")) {
throw new Error(".Z payload exceeds output cap — possible decompression bomb or undersized limit", { cause: err });
}
throw err;
} Prevention
- Set maxOutput from the true expected decompressed size, never the compressed size.
- Keep a limit for untrusted inputs and treat exceedance as a bomb signal.
- Raise the cap deliberately for known-large legacy .Z files.
- Don't hard-code tiny limits shared across all archives.
When it happens
Trigger: Calling lzwDecompress(bytes, maxOutput) where the .Z stream's decompressed size exceeds maxOutput; decoding an untrusted, highly compressible input with a small limit.
Common situations: Decompressing untrusted uploads with a conservative cap; legacy .Z files larger than a hard-coded limit; accidentally passing bytes.byteLength instead of the expected output size as maxOutput.
Related errors
- Truncated compress (.Z) code group
- Invalid non-zero compress (.Z) padding
- Truncated compress (.Z) header
- Invalid compress (.Z) output limit
- Invalid compress (.Z) header
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/4bc2d7fa8fea6798.
Report an issue: GitHub.