can1357/oh-my-pi · error · ArchiveError
Invalid XZ stream: block CRC32 mismatch
Error message
Invalid XZ stream: block CRC32 mismatch
What it means
XZ blocks store an integrity check selected at stream level; check ID 1 is CRC32. After decoding a block, the library recomputes CRC32 over the uncompressed output and compares it to the 4 bytes stored in the block. A mismatch means the decoded data differs from what the encoder hashed — the stream is corrupt or was modified.
Source
Thrown at packages/utils/src/ar/codecs/xz.ts:414
break;
case 9:
sparcDecode(bytes, startOffset);
break;
case 10:
arm64Decode(bytes, startOffset);
break;
case 11:
riscvDecode(bytes, startOffset);
break;
default:
throw new ArchiveError(`Unsupported XZ filter ID 0x${filter.id.toString(16)}`);
}
}
function verifyCheck(checkId: number, output: Uint8Array, expected: Uint8Array): void {
if (checkId === 0) return;
if (checkId === 1) {
if (read32LE(expected, 0) !== crc32(output)) throw new ArchiveError("Invalid XZ stream: block CRC32 mismatch");
return;
}
if (checkId === 4) {
const actual = crc64(output);
let stored = 0n;
for (let index = 0; index < 8; index++) stored |= BigInt(expected[index]!) << BigInt(index * 8);
if (actual !== stored) throw new ArchiveError("Invalid XZ stream: block CRC64 mismatch");
return;
}
const actual = new Uint8Array(new Bun.CryptoHasher("sha256").update(output).digest());
if (!equalBytes(actual, expected)) throw new ArchiveError("Invalid XZ stream: block SHA-256 mismatch");
}
async function decodeBlock(bytes: Uint8Array, offset: number, record: XzRecord, checkId: number): Promise<Uint8Array> {
if (offset >= bytes.byteLength || bytes[offset] === 0)
throw new ArchiveError("Invalid XZ stream: missing block header");
const headerSize = (bytes[offset]! + 1) * 4;
if (offset + headerSize > bytes.byteLength || headerSize < 8)View on GitHub (pinned to 9690622007)
Solutions
- Re-obtain the archive from its source — this error means the data is damaged, not that decoding options are wrong
- Verify externally with `xz -t` to confirm corruption independent of this library
- Check for incomplete downloads (size mismatch, interrupted transfer) and retry the transfer
- If corruption recurs from the same producer, re-compress and re-verify the data at the source
Example fix
// before: retrying the same corrupt bytes in a loop
while (tries < 3) decodeXz(sameCorruptBuffer);
// after: fetch a fresh copy once integrity fails
catch (e) { if (String(e.message).includes('CRC32 mismatch')) return downloadFreshArchive(); } Defensive patterns
Strategy: try-catch
Validate before calling
// Verify archive integrity before decode
const t = await $`xz -t archive.xz`.quiet().nothrow();
if (t.exitCode !== 0) throw new Error('archive.xz failed integrity check'); Type guard
null
Try / catch
try {
return await decodeXz(bytes);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes('CRC32 mismatch')) {
throw new Error('XZ block data is corrupt (CRC32); re-obtain the archive');
}
throw err;
} Prevention
- Compare file size/checksum against the source before decoding
- Retry downloads on unstable networks and verify after transfer
- Never mutate decompressed bytes and expect checks to pass — the check is over decoder output only
- Log the archive's origin so corrupt sources can be identified and fixed
When it happens
Trigger: Decompressing an XZ stream whose stream-flags declare check type CRC32 (check ID 1) and a block's stored CRC32 does not match the CRC32 of the block's decoded output.
Common situations: Truncated or partially downloaded .xz files; disk corruption; a stream edited after compression; decompressor bugs producing wrong output (rare).
Related errors
- Invalid XZ stream: block CRC64 mismatch
- Invalid XZ stream: block SHA-256 mismatch
- Invalid XZ stream: block header CRC32 mismatch
- ARJ member '${memberPath}' failed CRC32 verification
- Invalid XZ stream: padding without a stream
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/2467065e8061f38f.
Report an issue: GitHub.