{"record":{"id":"a3ad5116f0ad72af","repo":"can1357/oh-my-pi","slug":"invalid-xz-stream-padding-without-a-stream","errorCode":null,"errorMessage":"Invalid XZ stream: padding without a stream","messagePattern":"Invalid XZ stream: padding without a stream","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/codecs/xz.ts","lineNumber":116,"sourceCode":"\t\trecords.push({ unpaddedSize, uncompressedSize });\n\t}\n\twhile (cursor.pos < cursor.limit)\n\t\tif (bytes[cursor.pos++] !== 0) throw new ArchiveError(\"Invalid XZ stream: non-zero index padding\");\n\treturn records;\n}\n\nfunction discoverStreams(bytes: Uint8Array): XzStream[] {\n\tif (bytes.byteLength === 0 || (bytes.byteLength & 3) !== 0)\n\t\tthrow new ArchiveError(\"Invalid XZ stream: size is not a multiple of four bytes\");\n\tconst streams: XzStream[] = [];\n\tlet end = bytes.byteLength;\n\twhile (end > 0) {\n\t\tlet padding = 0;\n\t\twhile (end >= 4 && bytes[end - 1] === 0 && bytes[end - 2] === 0 && bytes[end - 3] === 0 && bytes[end - 4] === 0) {\n\t\t\tend -= 4;\n\t\t\tpadding += 4;\n\t\t}\n\t\tif (end === 0) throw new ArchiveError(\"Invalid XZ stream: padding without a stream\");\n\t\tif (end < 24) throw new ArchiveError(\"Invalid XZ stream: truncated stream framing\");\n\t\tconst footerStart = end - 12;\n\t\tif (bytes[footerStart + 10] !== 0x59 || bytes[footerStart + 11] !== 0x5a)\n\t\t\tthrow new ArchiveError(\"Invalid XZ stream: footer magic mismatch\");\n\t\tif (crc32(bytes.subarray(footerStart + 4, footerStart + 10)) !== read32LE(bytes, footerStart))\n\t\t\tthrow new ArchiveError(\"Invalid XZ stream: footer CRC32 mismatch\");\n\t\tconst flag0 = bytes[footerStart + 8]!;\n\t\tconst flag1 = bytes[footerStart + 9]!;\n\t\tif (flag0 !== 0 || (flag1 & 0xf0) !== 0) throw new ArchiveError(\"Unsupported XZ stream flags\");\n\t\tconst checkId = flag1 & 0x0f;\n\t\tcheckSize(checkId);\n\t\tconst indexSize = (read32LE(bytes, footerStart + 4) + 1) * 4;\n\t\tif (!Number.isSafeInteger(indexSize) || indexSize > footerStart)\n\t\t\tthrow new ArchiveError(\"Invalid XZ stream: backward index size is invalid\");\n\t\tconst indexStart = footerStart - indexSize;\n\t\tconst records = parseIndex(bytes, indexStart, indexSize);\n\t\tlet blocksSize = 0;\n\t\tfor (const record of records) {","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/codecs/xz.ts#L98-L134","documentation":"discoverStreams() walks the buffer backwards from the end, peeling off 4-byte-aligned zero padding between concatenated XZ streams before parsing each stream footer. If the zero-padding strip consumes the entire buffer, there is no stream left to parse — the input is all zeros (or ends in zeros with nothing before them). The library throws ArchiveError to signal the byte buffer is not a decodable XZ container.","triggerScenarios":"Calling the xz codec (via streams()/discoverStreams) with a buffer consisting entirely of zero bytes, or a concatenated-streams buffer whose trailing zero padding runs back to offset 0 with no stream footer preceding it. Also triggered by a truncated file where only padding bytes survived.","commonSituations":"Reading an empty/zero-filled .xz file (e.g. sparse file, failed download writing zeros), passing the wrong buffer offset/length so only a padding region is handed to the decoder, or corruption that zeroed the stream data.","solutions":["Verify the buffer starts with the XZ magic bytes fd 37 7a 58 5a 00 before decoding","Check the file is a complete, non-empty .xz file (re-download or re-compress)","Confirm you are slicing the correct byte range of a multi-stream archive","If handling concatenated streams yourself, ensure each stream's full bytes are included"],"exampleFix":"// before\nconst bytes = new Uint8Array(await Bun.file(path).arrayBuffer()).subarray(wrongOffset);\nawait xzDecode(bytes); // all-zero slice -> throws\n// after\nconst bytes = new Uint8Array(await Bun.file(path).arrayBuffer());\nif (!equalBytes(bytes.subarray(0, 6), Uint8Array.of(0xfd,0x37,0x7a,0x58,0x5a,0x00))) throw new Error(\"not an xz file\");\nawait xzDecode(bytes);","handlingStrategy":"validation","validationCode":"function looksLikeXz(bytes: Uint8Array): boolean {\n  const magic = Uint8Array.of(0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00);\n  if (bytes.byteLength < 24 || bytes.byteLength % 4 !== 0) return false;\n  return magic.every((b, i) => bytes[i] === b) || bytes.some((b) => b !== 0);\n}","typeGuard":"null","tryCatchPattern":"try {\n  const out = await xzDecode(bytes);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes(\"padding without a stream\")) {\n    throw new Error(\"Input is not an XZ stream (all padding/empty)\");\n  }\n  throw err;\n}","preventionTips":["Check the XZ magic bytes before decoding","Ensure files are fully transferred and non-empty","Don't hand slices of multi-stream buffers to the decoder; pass whole buffers"],"tags":["xz","archive","corrupt-input","validation"],"backgroundTag":"invalid-archive-format","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}