can1357/oh-my-pi · error · ArchiveError
Invalid XZ stream: header and footer flags differ
Error message
Invalid XZ stream: header and footer flags differ
What it means
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.
Source
Thrown at packages/utils/src/ar/codecs/xz.ts:143
if (flag0 !== 0 || (flag1 & 0xf0) !== 0) throw new ArchiveError("Unsupported XZ stream flags");
const checkId = flag1 & 0x0f;
checkSize(checkId);
const indexSize = (read32LE(bytes, footerStart + 4) + 1) * 4;
if (!Number.isSafeInteger(indexSize) || indexSize > footerStart)
throw new ArchiveError("Invalid XZ stream: backward index size is invalid");
const indexStart = footerStart - indexSize;
const records = parseIndex(bytes, indexStart, indexSize);
let blocksSize = 0;
for (const record of records) {
blocksSize += Math.ceil(record.unpaddedSize / 4) * 4;
if (!Number.isSafeInteger(blocksSize)) throw new ArchiveError("XZ stream uses sizes too large to read safely");
}
const start = indexStart - blocksSize - 12;
if (start < 0 || start + 12 > bytes.byteLength || !equalBytes(bytes.subarray(start, start + 6), XZ_MAGIC)) {
throw new ArchiveError("Invalid XZ stream: header position or magic is invalid");
}
if (bytes[start + 6] !== flag0 || bytes[start + 7] !== flag1)
throw new ArchiveError("Invalid XZ stream: header and footer flags differ");
if (crc32(bytes.subarray(start + 6, start + 8)) !== read32LE(bytes, start + 8))
throw new ArchiveError("Invalid XZ stream: header CRC32 mismatch");
streams.unshift({ start, indexStart, footerStart, checkId, records });
end = start;
void padding;
}
return streams;
}
interface XzFilter {
id: number;
properties: Uint8Array;
}
function deltaDecode(bytes: Uint8Array, distance: number): void {
const history = new Uint8Array(256);
let position = 0;
for (let index = 0; index < bytes.byteLength; index++) {View on GitHub (pinned to 9690622007)
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
Example fix
// before
header[6] = 0x01; // patched check type after the fact
await xzDecode(bytes); // header/footer flags differ
// after
// re-encode: $ xz --check=crc32 --format=xz -c in > out.xz
const bytes = new Uint8Array(await Bun.file("out.xz").arrayBuffer());
await xzDecode(bytes); Defensive patterns
Strategy: try-catch
Validate before calling
null
Type guard
null
Try / catch
try {
await xzDecode(bytes);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes("header and footer flags differ")) {
throw new Error("XZ header/footer inconsistent — re-compress the archive");
}
throw err;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Manual archive surgery/patching tools, merge scripts that concatenate partial streams, or bit-rot affecting a single byte.
Related errors
- Invalid XZ stream: padding without a stream
- Invalid XZ stream: footer magic mismatch
- Invalid XZ stream: footer CRC32 mismatch
- Invalid XZ stream: backward index size is invalid
- Invalid XZ stream: header position or magic is invalid
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/48760c0cdf599455.
Report an issue: GitHub.