{"record":{"id":"18f01430c46c8452","repo":"can1357/oh-my-pi","slug":"invalid-xz-stream-block-size-does-not-match-its-i","errorCode":null,"errorMessage":"Invalid XZ stream: block size does not match its index record","messagePattern":"Invalid XZ stream: block size does not match its index record","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/codecs/xz.ts","lineNumber":483,"sourceCode":"\tif (checkStart + integritySize > bytes.byteLength) throw new ArchiveError(\"Invalid XZ stream: truncated block data\");\n\tconst last = filters[filters.length - 1]!;\n\tif (last.id !== 0x21 || last.properties.byteLength !== 1)\n\t\tthrow new ArchiveError(`Unsupported XZ terminal filter ID 0x${last.id.toString(16)} (LZMA2 required)`);\n\tlet output = await lzma2Decompress(\n\t\tlast.properties[0]!,\n\t\tbytes.subarray(compressedStart, compressedEnd),\n\t\trecord.uncompressedSize,\n\t);\n\tif (output.byteLength !== record.uncompressedSize)\n\t\tthrow new ArchiveError(\"Invalid XZ stream: decoded block size mismatch\");\n\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)","sourceCodeStart":465,"sourceCodeEnd":501,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/codecs/xz.ts#L465-L501","documentation":"This ArchiveError is thrown while decoding an XZ block when the block's actual end (check data end) does not line up with the padded block size recorded in the stream index. The index record's unpaddedSize (rounded up to a 4-byte boundary) must exactly match where the block's integrity check ends; a mismatch means the stream is corrupt or the index/block pairing is broken.","triggerScenarios":"Calling xzDecompress (or decoding a .tar.xz/.xz payload) on bytes whose block header/check region and index records disagree — e.g. corrupted archive data, a hand-truncated or spliced XZ file, or an index from a different stream.","commonSituations":"Partially downloaded or truncated .xz files; byte-level edits to archives; concatenated streams where a block from one stream is paired with an index from another; files damaged in transfer.","solutions":["Re-download or re-extract the archive from a trusted source","Verify the file's checksum against the publisher's published hash","Test the file with a standalone tool (xz -t) to confirm corruption before reporting a bug","If concatenating XZ streams yourself, keep each stream's blocks and index intact"],"exampleFix":"// before: trusting a partially downloaded file\nawait xzDecompress(truncatedBytes, limit);\n// after: validate integrity first\nif ((await Bun.file(path).slice(0).arrayBuffer()) && !(await fileChecksumMatches(path))) throw new Error('archive corrupt');\nawait xzDecompress(bytes, limit);","handlingStrategy":"validation","validationCode":"import { isXz } from '@oh-my-pi/pi-utils/ar/codecs/xz';\nif (!isXz(bytes)) throw new Error('input is not XZ');\n// trust boundary: pre-check integrity out of band (xz -t or published checksum)","typeGuard":null,"tryCatchPattern":"try {\n  const out = await xzDecompress(bytes, limit);\n} catch (err) {\n  if (err instanceof ArchiveError && /block size does not match/.test(err.message)) {\n    // treat as corrupt archive: surface to user / re-fetch\n  } else throw err;\n}","preventionTips":["Verify archive checksums before decompressing","Never splice or hand-edit XZ stream bytes","Use xz -t as an independent pre-flight check on untrusted archives"],"tags":["xz","archive","corruption","decompression"],"backgroundTag":"xz-stream-corrupt","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}