{"record":{"id":"d3b68c306d9091e0","repo":"can1357/oh-my-pi","slug":"invalid-xz-stream-block-header-crc32-mismatch","errorCode":null,"errorMessage":"Invalid XZ stream: block header CRC32 mismatch","messagePattern":"Invalid XZ stream: block header CRC32 mismatch","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/codecs/xz.ts","lineNumber":435,"sourceCode":"\tif (checkId === 4) {\n\t\tconst actual = crc64(output);\n\t\tlet stored = 0n;\n\t\tfor (let index = 0; index < 8; index++) stored |= BigInt(expected[index]!) << BigInt(index * 8);\n\t\tif (actual !== stored) throw new ArchiveError(\"Invalid XZ stream: block CRC64 mismatch\");\n\t\treturn;\n\t}\n\tconst actual = new Uint8Array(new Bun.CryptoHasher(\"sha256\").update(output).digest());\n\tif (!equalBytes(actual, expected)) throw new ArchiveError(\"Invalid XZ stream: block SHA-256 mismatch\");\n}\n\nasync function decodeBlock(bytes: Uint8Array, offset: number, record: XzRecord, checkId: number): Promise<Uint8Array> {\n\tif (offset >= bytes.byteLength || bytes[offset] === 0)\n\t\tthrow new ArchiveError(\"Invalid XZ stream: missing block header\");\n\tconst headerSize = (bytes[offset]! + 1) * 4;\n\tif (offset + headerSize > bytes.byteLength || headerSize < 8)\n\t\tthrow new ArchiveError(\"Invalid XZ stream: truncated block header\");\n\tif (crc32(bytes.subarray(offset, offset + headerSize - 4)) !== read32LE(bytes, offset + headerSize - 4))\n\t\tthrow new ArchiveError(\"Invalid XZ stream: block header CRC32 mismatch\");\n\tconst cursor: Cursor = { bytes, pos: offset + 1, limit: offset + headerSize - 4 };\n\tconst flags = bytes[cursor.pos++]!;\n\tif ((flags & 0x3c) !== 0) throw new ArchiveError(\"Unsupported XZ block flags\");\n\tconst filterCount = (flags & 3) + 1;\n\tconst declaredCompressed = (flags & 0x40) !== 0 ? readVarInt(cursor) : undefined;\n\tconst declaredUncompressed = (flags & 0x80) !== 0 ? readVarInt(cursor) : undefined;\n\tconst filters: XzFilter[] = [];\n\tfor (let index = 0; index < filterCount; index++) {\n\t\tconst id = readVarInt(cursor);\n\t\tconst propertySize = readVarInt(cursor);\n\t\tif (propertySize > cursor.limit - cursor.pos)\n\t\t\tthrow new ArchiveError(\"Invalid XZ stream: truncated filter properties\");\n\t\tfilters.push({ id, properties: bytes.slice(cursor.pos, cursor.pos + propertySize) });\n\t\tcursor.pos += propertySize;\n\t}\n\twhile (cursor.pos < cursor.limit)\n\t\tif (bytes[cursor.pos++] !== 0) throw new ArchiveError(\"Invalid XZ stream: non-zero block header padding\");\n\tconst integritySize = checkSize(checkId);","sourceCodeStart":417,"sourceCodeEnd":453,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/codecs/xz.ts#L417-L453","documentation":"Every XZ block header ends with a CRC32 of the header bytes that precede it. The library computes CRC32 over headerSize-4 bytes and compares with the trailing little-endian 4 bytes. A mismatch means the block header bytes were altered after encoding — the header is corrupt even if structurally parseable.","triggerScenarios":"Decoding an XZ stream where any byte in a block header (size byte, flags, filter definitions) was modified, so the header's trailing CRC32 no longer matches.","commonSituations":"Byte-level corruption from bad storage/transfer; deliberate tampering; buggy tools that patch archive headers in place.","solutions":["Replace the file with a known-good copy; header CRC failure means the bytes are damaged, not misconfigured","Verify with `xz -t file.xz` to confirm corruption independently","Re-compress from original data if no good copy exists","If input is untrusted, reject with a clear 'corrupt archive' message rather than attempting repair"],"exampleFix":"// before: hand-patching a block header byte\nbuf[offset + 2] = 0x21; // tweak filter flags\nawait decodeXz(buf);\n// after: recompute or, better, re-compress the archive properly\n// $ xz -k -f file.bin && use the fresh file.xz","handlingStrategy":"try-catch","validationCode":"const t = await $`xz -t archive.xz`.quiet().nothrow();\nif (t.exitCode !== 0) throw new Error('archive.xz header integrity check failed');","typeGuard":"null","tryCatchPattern":"try {\n  return await decodeXz(bytes);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes('block header CRC32 mismatch')) {\n    throw new Error('XZ block header corrupted (header CRC32); archive is damaged');\n  }\n  throw err;\n}","preventionTips":["Never patch bytes inside compressed archives; re-compress instead","Verify transfer integrity end-to-end (checksums from source)","Keep archives off known-failing storage; watch for repeated corruption patterns","Fail closed on header CRC errors — the payload cannot be trusted either"],"tags":["xz","archive","crc","header","corrupt-input"],"backgroundTag":"checksum-mismatch","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}