{"record":{"id":"48760c0cdf599455","repo":"can1357/oh-my-pi","slug":"invalid-xz-stream-header-and-footer-flags-differ","errorCode":null,"errorMessage":"Invalid XZ stream: header and footer flags differ","messagePattern":"Invalid XZ stream: header and footer flags differ","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/codecs/xz.ts","lineNumber":143,"sourceCode":"\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\");\n\t\t}\n\t\tif (bytes[start + 6] !== flag0 || bytes[start + 7] !== flag1)\n\t\t\tthrow new ArchiveError(\"Invalid XZ stream: header and footer flags differ\");\n\t\tif (crc32(bytes.subarray(start + 6, start + 8)) !== read32LE(bytes, start + 8))\n\t\t\tthrow new ArchiveError(\"Invalid XZ stream: header CRC32 mismatch\");\n\t\tstreams.unshift({ start, indexStart, footerStart, checkId, records });\n\t\tend = start;\n\t\tvoid padding;\n\t}\n\treturn streams;\n}\n\ninterface XzFilter {\n\tid: number;\n\tproperties: Uint8Array;\n}\n\nfunction deltaDecode(bytes: Uint8Array, distance: number): void {\n\tconst history = new Uint8Array(256);\n\tlet position = 0;\n\tfor (let index = 0; index < bytes.byteLength; index++) {","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/codecs/xz.ts#L125-L161","documentation":"The XZ spec requires the stream header flags and stream footer flags to be identical. discoverStreams() compares the header's flag bytes (start+6, start+7) against those read from the footer; a mismatch means the header and footer belong to different streams or one of them was modified, so the archive is internally inconsistent.","triggerScenarios":"Splicing a footer from one .xz onto blocks/index/header of another; editing check-type flags after compression without regenerating both; corruption touching only one of the two flag locations.","commonSituations":"Manual archive surgery/patching tools, merge scripts that concatenate partial streams, or bit-rot affecting a single byte.","solutions":["Re-compress the data to regenerate a consistent header/footer pair","Verify with xz -t and restore from backup/checksum if the file is damaged","Never edit stream flags post-compression; change check type only via encoder options (xz --check=...)","When concatenating streams, keep each stream's header/index/footer intact as a unit"],"exampleFix":"// before\nheader[6] = 0x01; // patched check type after the fact\nawait xzDecode(bytes); // header/footer flags differ\n// after\n// re-encode: $ xz --check=crc32 --format=xz -c in > out.xz\nconst bytes = new Uint8Array(await Bun.file(\"out.xz\").arrayBuffer());\nawait xzDecode(bytes);","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"null","tryCatchPattern":"try {\n  await xzDecode(bytes);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes(\"header and footer flags differ\")) {\n    throw new Error(\"XZ header/footer inconsistent — re-compress the archive\");\n  }\n  throw err;\n}","preventionTips":["Never edit stream flags after compression; re-encode with the desired check type","Keep each stream's header/index/footer together when moving data","Validate archives with xz -t before processing"],"tags":["xz","archive","consistency","corrupt-input"],"backgroundTag":"invalid-archive-format","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}