can1357/oh-my-pi · error · ArchiveError

Invalid XZ stream: block compressed size mismatch

Error message

Invalid XZ stream: block compressed size mismatch

What it means

The block header optionally declares the compressed size (flags bit 0x40). When present, it must equal the size computed from the index record (unpaddedSize - headerSize - integritySize). A mismatch means the index and header disagree, so the stream is corrupt or non-conforming.

Source

Thrown at packages/utils/src/ar/codecs/xz.ts:458

	const declaredCompressed = (flags & 0x40) !== 0 ? readVarInt(cursor) : undefined;
	const declaredUncompressed = (flags & 0x80) !== 0 ? readVarInt(cursor) : undefined;
	const filters: XzFilter[] = [];
	for (let index = 0; index < filterCount; index++) {
		const id = readVarInt(cursor);
		const propertySize = readVarInt(cursor);
		if (propertySize > cursor.limit - cursor.pos)
			throw new ArchiveError("Invalid XZ stream: truncated filter properties");
		filters.push({ id, properties: bytes.slice(cursor.pos, cursor.pos + propertySize) });
		cursor.pos += propertySize;
	}
	while (cursor.pos < cursor.limit)
		if (bytes[cursor.pos++] !== 0) throw new ArchiveError("Invalid XZ stream: non-zero block header padding");
	const integritySize = checkSize(checkId);
	const compressedSize = record.unpaddedSize - headerSize - integritySize;
	if (!Number.isSafeInteger(compressedSize) || compressedSize <= 0)
		throw new ArchiveError("Invalid XZ stream: compressed block size is invalid");
	if (declaredCompressed !== undefined && declaredCompressed !== compressedSize)
		throw new ArchiveError("Invalid XZ stream: block compressed size mismatch");
	if (declaredUncompressed !== undefined && declaredUncompressed !== record.uncompressedSize)
		throw new ArchiveError("Invalid XZ stream: block uncompressed size mismatch");
	const compressedStart = offset + headerSize;
	const compressedEnd = compressedStart + compressedSize;
	const paddingSize = (4 - ((headerSize + compressedSize) & 3)) & 3;
	const checkStart = compressedEnd + paddingSize;
	if (checkStart + integritySize > bytes.byteLength) throw new ArchiveError("Invalid XZ stream: truncated block data");
	const last = filters[filters.length - 1]!;
	if (last.id !== 0x21 || last.properties.byteLength !== 1)
		throw new ArchiveError(`Unsupported XZ terminal filter ID 0x${last.id.toString(16)} (LZMA2 required)`);
	let output = await lzma2Decompress(
		last.properties[0]!,
		bytes.subarray(compressedStart, compressedEnd),
		record.uncompressedSize,
	);
	if (output.byteLength !== record.uncompressedSize)
		throw new ArchiveError("Invalid XZ stream: decoded block size mismatch");
	output = output.slice();

View on GitHub (pinned to 9690622007)

Solutions

  1. Re-acquire a known-good copy of the archive and verify with `xz -t`.
  2. If the file was produced by your own tooling, fix the encoder to keep the header-declared sizes and index records consistent.
  3. Check for accidental byte-level modification of the archive (editors, transfer encodings, text-mode copies).
  4. Catch ArchiveError around xzDecompress and report the specific file as invalid.
Defensive patterns

Strategy: validation

Validate before calling

const ok = await $`xz -t ${path}`.quiet().nothrow();
if (ok.exitCode !== 0) throw new Error(`XZ archive failed integrity test: ${path}`);

Try / catch

try {
	return await xzDecompress(bytes, maxOutput);
} catch (err) {
	if (err instanceof ArchiveError && /mismatch/i.test(err.message)) {
		throw new Error('Archive metadata inconsistent — file is corrupt, re-obtain it');
	}
	throw err;
}

Prevention

When it happens

Trigger: xzDecompress reads a block header with the compressed-size-present flag set whose declared value differs from record.unpaddedSize - headerSize - integritySize.

Common situations: Archives damaged in transit or on disk, files produced by encoders that write inconsistent index records, or streams reassembled from fragments.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/ac86d661213933da. Report an issue: GitHub.