{"record":{"id":"07fb5c49d52c8052","repo":"can1357/oh-my-pi","slug":"invalid-xz-stream-footer-crc32-mismatch","errorCode":null,"errorMessage":"Invalid XZ stream: footer CRC32 mismatch","messagePattern":"Invalid XZ stream: footer CRC32 mismatch","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/codecs/xz.ts","lineNumber":122,"sourceCode":"\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) {\n\t\t\tblocksSize += Math.ceil(record.unpaddedSize / 4) * 4;\n\t\t\tif (!Number.isSafeInteger(blocksSize)) throw new ArchiveError(\"XZ stream uses sizes too large to read safely\");\n\t\t}\n\t\tconst start = indexStart - blocksSize - 12;\n\t\tif (start < 0 || start + 12 > bytes.byteLength || !equalBytes(bytes.subarray(start, start + 6), XZ_MAGIC)) {\n\t\t\tthrow new ArchiveError(\"Invalid XZ stream: header position or magic is invalid\");","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/codecs/xz.ts#L104-L140","documentation":"The XZ stream footer stores a CRC32 of its stream-flag bytes plus the backward-index size. discoverStreams() recomputes the CRC32 over footer bytes 4..10 and compares it to the stored value; a mismatch means the footer (or its CRC field) was modified or corrupted, so the stream cannot be trusted.","triggerScenarios":"Any single-bit or multi-byte corruption within the 12-byte footer (CRC field at footerStart+0..3, flags at +8..9, backward size at +4..7, or the CRC-covered region), or a buffer slice misaligned by a few bytes so fields are read from wrong offsets.","commonSituations":"Faulty downloads/transfers, disk errors, files modified after compression (e.g. by a tool that patched bytes), or manual buffer slicing with wrong offsets in multi-stream archives.","solutions":["Re-download or restore the file and verify its checksum (e.g. sha256 against the source)","If slicing buffers manually, verify the footer offset is exactly end-12 for the stream","Re-compress the data from the original source if the original is damaged","Test the file with the xz CLI (xz -t) to confirm corruption independent of this library"],"exampleFix":"// before\nconst slice = whole.subarray(6); // misaligned\nawait xzDecode(slice); // footer CRC mismatch\n// after\nconst slice = whole.subarray(0); // keep stream-aligned offsets\nawait xzDecode(slice);","handlingStrategy":"try-catch","validationCode":"// Pre-screen with an external tool when available:\n// $ xz -t file.xz && echo ok","typeGuard":"null","tryCatchPattern":"try {\n  await xzDecode(bytes);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes(\"footer CRC32 mismatch\")) {\n    throw new Error(\"XZ footer corrupted — re-acquire the archive\");\n  }\n  throw err;\n}","preventionTips":["Verify checksums after download/transfer","Avoid editing compressed files in place","Test archives with xz -t before processing"],"tags":["xz","archive","checksum","corrupt-input"],"backgroundTag":"checksum-mismatch","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}