{"record":{"id":"4bc2d7fa8fea6798","repo":"can1357/oh-my-pi","slug":"compress-z-output-exceeds-the-this-limit-by","errorCode":null,"errorMessage":"Compress (.Z) output exceeds the ${this.#limit}-byte limit","messagePattern":"Compress \\(\\.Z\\) output exceeds the (.+?)-byte limit","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/codecs/lzw.ts","lineNumber":81,"sourceCode":"\t\tthis.#limit = limit;\n\t\tthis.#bytes = new Uint8Array(Math.min(limit, Math.max(64, Math.min(inputSize * 2, 64 * 1024))));\n\t}\n\n\tappendReversed(stack: Uint8Array, length: number): void {\n\t\tthis.#ensure(length);\n\t\tfor (let index = length - 1; index >= 0; index--) {\n\t\t\tthis.#bytes[this.#length++] = stack[index]!;\n\t\t}\n\t}\n\n\tfinish(): Uint8Array {\n\t\treturn this.#bytes.slice(0, this.#length);\n\t}\n\n\t#ensure(additional: number): void {\n\t\tconst needed = this.#length + additional;\n\t\tif (!Number.isSafeInteger(needed) || needed > this.#limit) {\n\t\t\tthrow new ArchiveError(`Compress (.Z) output exceeds the ${this.#limit}-byte limit`);\n\t\t}\n\t\tif (needed <= this.#bytes.byteLength) {\n\t\t\treturn;\n\t\t}\n\t\tlet capacity = Math.max(needed, Math.min(this.#limit, Math.max(64, this.#bytes.byteLength * 2)));\n\t\tif (capacity > this.#limit) {\n\t\t\tcapacity = this.#limit;\n\t\t}\n\t\tconst grown = new Uint8Array(capacity);\n\t\tgrown.set(this.#bytes.subarray(0, this.#length));\n\t\tthis.#bytes = grown;\n\t}\n}\n\nfunction decode(bytes: Uint8Array, maxOutput: number): Uint8Array {\n\tif (!Number.isSafeInteger(maxOutput) || maxOutput < 0) {\n\t\tthrow new ArchiveError(\"Invalid compress (.Z) output limit\");\n\t}","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/codecs/lzw.ts#L63-L99","documentation":"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.","triggerScenarios":"Calling lzwDecompress(bytes, maxOutput) where the .Z stream's decompressed size exceeds maxOutput; decoding an untrusted, highly compressible input with a small limit.","commonSituations":"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.","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."],"exampleFix":"// before\nlzwDecompress(bytes, bytes.byteLength);\n// after: output can be larger than input; use a real bound\nlzwDecompress(bytes, 256 * 1024 * 1024);","handlingStrategy":"validation","validationCode":"// Know the decompressed size before decoding, or pick a generous bound\nconst maxOutput = knownUncompressedSize ?? 256 * 1024 * 1024;\nif (!Number.isSafeInteger(maxOutput) || maxOutput < 0) throw new Error(\"Invalid maxOutput\");","typeGuard":null,"tryCatchPattern":"try {\n  return lzwDecompress(bytes, maxOutput);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes(\"-byte limit\")) {\n    throw new Error(\".Z payload exceeds output cap — possible decompression bomb or undersized limit\", { cause: err });\n  }\n  throw err;\n}","preventionTips":["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."],"tags":["archive","lzw","compress-z","limit-exceeded","zip-bomb"],"backgroundTag":"decompression-limit-exceeded","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}