can1357/oh-my-pi · error · ArchiveError
Invalid XZ stream: header CRC32 mismatch
Error message
Invalid XZ stream: header CRC32 mismatch
What it means
The XZ stream header ends with a CRC32 of its two flag bytes. discoverStreams() recomputes the CRC over header bytes start+6..start+8 and compares it to the stored value; a mismatch means the header was altered or corrupted after encoding, so the library refuses to register the stream.
Source
Thrown at packages/utils/src/ar/codecs/xz.ts:145
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++) {
const value = (bytes[index]! + history[(distance + position) & 0xff]!) & 0xff;
history[position] = value;View on GitHub (pinned to 9690622007)
Solutions
- Verify the file with xz -t / checksum and re-download or restore from backup
- Re-compress from original data to regenerate a valid header
- Avoid post-compression byte edits; change encoder settings and re-encode instead
- If inputs are untrusted, validate archives in a sandbox before processing
Example fix
// before
bytes[8] = 0x42; // header edit without CRC fix
await xzDecode(bytes);
// after
// regenerate: $ xz -c --check=crc64 in > fixed.xz
const bytes = new Uint8Array(await Bun.file("fixed.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 CRC32 mismatch")) {
throw new Error("XZ stream header corrupted — restore or re-compress the archive");
}
throw err;
} Prevention
- Verify checksums after transfer
- Avoid post-compression byte edits
- Re-encode with xz rather than patching headers
When it happens
Trigger: Corruption or tampering within the 12-byte stream header (magic, flags, or CRC field), a splice that pairs a header from one file with a body from another while flags coincidentally match, or a fuzzed archive.
Common situations: Damaged downloads/storage, files modified by tools that rewrite header bytes without fixing CRC, or maliciously crafted inputs.
Related errors
- Invalid XZ stream: footer CRC32 mismatch
- Invalid XZ stream: padding without a stream
- Invalid XZ stream: footer magic 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/047a9f2c19c6f9f1.
Report an issue: GitHub.