{"record":{"id":"bd6b23bae6acb408","repo":"can1357/oh-my-pi","slug":"invalid-xz-output-limit","errorCode":null,"errorMessage":"Invalid XZ output limit","messagePattern":"Invalid XZ output limit","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/codecs/xz.ts","lineNumber":494,"sourceCode":"\toutput = output.slice();\n\tfor (let index = filters.length - 2; index >= 0; index--) applyFilter(output, filters[index]!);\n\tfor (let index = compressedEnd; index < checkStart; index++)\n\t\tif (bytes[index] !== 0) throw new ArchiveError(\"Invalid XZ stream: non-zero block padding\");\n\tverifyCheck(checkId, output, bytes.subarray(checkStart, checkStart + integritySize));\n\tconst paddedEnd = offset + Math.ceil(record.unpaddedSize / 4) * 4;\n\tif (checkStart + integritySize !== paddedEnd)\n\t\tthrow new ArchiveError(\"Invalid XZ stream: block size does not match its index record\");\n\treturn output;\n}\n\n/** Whether bytes begin with the XZ stream-header magic. */\nexport function isXz(bytes: Uint8Array): boolean {\n\treturn bytes.byteLength >= XZ_MAGIC.byteLength && equalBytes(bytes.subarray(0, XZ_MAGIC.byteLength), XZ_MAGIC);\n}\n\n/** Decompress all concatenated streams in an XZ container within `maxOutput`. */\nexport async function xzDecompress(bytes: Uint8Array, maxOutput: number): Promise<Uint8Array> {\n\tif (!Number.isSafeInteger(maxOutput) || maxOutput < 0) throw new ArchiveError(\"Invalid XZ output limit\");\n\ttry {\n\t\tconst streams = discoverStreams(bytes);\n\t\tlet totalSize = 0;\n\t\tfor (const stream of streams)\n\t\t\tfor (const record of stream.records) {\n\t\t\t\ttotalSize += record.uncompressedSize;\n\t\t\t\tif (!Number.isSafeInteger(totalSize) || totalSize > maxOutput)\n\t\t\t\t\tthrow new ArchiveError(\"XZ output exceeds its size limit\");\n\t\t\t}\n\t\tconst output = new Uint8Array(totalSize);\n\t\tlet outputPosition = 0;\n\t\tfor (const stream of streams) {\n\t\t\tlet blockPosition = stream.start + 12;\n\t\t\tfor (const record of stream.records) {\n\t\t\t\tconst block = await decodeBlock(bytes, blockPosition, record, stream.checkId);\n\t\t\t\toutput.set(block, outputPosition);\n\t\t\t\toutputPosition += block.byteLength;\n\t\t\t\tblockPosition += Math.ceil(record.unpaddedSize / 4) * 4;","sourceCodeStart":476,"sourceCodeEnd":512,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/codecs/xz.ts#L476-L512","documentation":"Thrown when the maxOutput argument passed to xzDecompress is not a valid non-negative safe integer. The limit is validated up front before any decoding work happens, so this is a caller-side input bug, not a data problem.","triggerScenarios":"Calling xzDecompress(bytes, maxOutput) with NaN, a negative number, a float, a non-integer, or a value beyond Number.MAX_SAFE_INTEGER.","commonSituations":"maxOutput read from misparsed config/CLI args (e.g. parseInt returning NaN); unit confusion (MiB vs bytes producing fractional values); unbounded defaults like -1 or Infinity.","solutions":["Pass a non-negative safe integer, e.g. 64 * 1024 * 1024","Sanitize the value first: maxOutput = Math.floor(Number(x)); check Number.isSafeInteger","Fix the config/flag parsing that produced the bad value"],"exampleFix":"// before\nawait xzDecompress(bytes, Number(opts.maxMb) * 1024); // NaN if opts.maxMb undefined\n// after\nconst limit = Math.max(0, Math.floor(Number(opts.maxMb ?? 64) * 1024 * 1024));\nawait xzDecompress(bytes, limit);","handlingStrategy":"validation","validationCode":"function validLimit(n: unknown): n is number {\n  return typeof n === 'number' && Number.isSafeInteger(n) && n >= 0;\n}\nif (!validLimit(maxOutput)) throw new TypeError(`bad maxOutput: ${maxOutput}`);","typeGuard":"function isSizeLimit(v: unknown): v is number {\n  return typeof v === 'number' && Number.isSafeInteger(v) && v >= 0;\n}","tryCatchPattern":"try {\n  const out = await xzDecompress(bytes, limit);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message === 'Invalid XZ output limit') {\n    // caller bug, not data bug: fix the limit value upstream\n  } else throw err;\n}","preventionTips":["Centralize limit parsing into one validated helper","Coerce config values with Math.floor(Number(x)) and validate","Never pass NaN/-1/Infinity as a size limit"],"tags":["xz","validation","arguments","decompression"],"backgroundTag":"invalid-size-limit-argument","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}