can1357/oh-my-pi · error · ArchiveError

Unsupported XZ block flags

Error message

Unsupported XZ block flags

What it means

The XZ block header's flags byte has bits 2-5 (0x3c) set, which are reserved by the XZ format and must be zero. This decoder strictly validates the format and rejects the block rather than guessing. It is thrown while parsing a block header inside xzDecompress/decodeBlock (packages/utils/src/ar/codecs/xz.ts:438).

Source

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

		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)
		throw new ArchiveError("Invalid XZ stream: truncated block header");
	if (crc32(bytes.subarray(offset, offset + headerSize - 4)) !== read32LE(bytes, offset + headerSize - 4))
		throw new ArchiveError("Invalid XZ stream: block header CRC32 mismatch");
	const cursor: Cursor = { bytes, pos: offset + 1, limit: offset + headerSize - 4 };
	const flags = bytes[cursor.pos++]!;
	if ((flags & 0x3c) !== 0) throw new ArchiveError("Unsupported XZ block flags");
	const filterCount = (flags & 3) + 1;
	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");

View on GitHub (pinned to 9690622007)

Solutions

  1. Re-download or restore the .xz file and verify its checksum against the published one.
  2. Test the file with `xz -t file.xz` (or `xz -l`) to confirm it is valid; re-compress with `xz` if the source encoder was non-standard.
  3. Ensure you are passing the full XZ stream bytes, not a slice starting mid-file, to xzDecompress.
  4. If you need reserved-flag XZ variants, they are out of scope for this decoder; use a full-featured XZ implementation.

Example fix

// before
await xzDecompress(partiallyDownloadedBytes, maxOutput);
// after
const bytes = await Bun.file('archive.tar.xz').bytes();
await xzDecompress(bytes, maxOutput); // complete, checksum-verified file
Defensive patterns

Strategy: try-catch

Validate before calling

import { isXz } from '@oh-my-pi/pi-utils/ar/codecs/xz';
if (!isXz(bytes)) throw new Error('Not an XZ stream');

Type guard

function isXzStream(bytes: Uint8Array): boolean {
	const magic = [0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00];
	return bytes.byteLength >= magic.length && magic.every((b, i) => bytes[i] === b);
}

Try / catch

import { ArchiveError } from '@oh-my-pi/pi-utils/ar';
try {
	const out = await xzDecompress(bytes, maxOutput);
} catch (err) {
	if (err instanceof ArchiveError) {
		logger.warn('XZ archive invalid, skipping', { message: err.message });
		return fallbackPath();
	}
	throw err;
}

Prevention

When it happens

Trigger: Calling xzDecompress (or an archive-extract API that routes to it) on bytes whose block header flags byte contains any of the reserved bits 0x3c — i.e. a corrupt, hand-edited, or non-conforming XZ file.

Common situations: Corrupted downloads (truncated then re-saved archives), files produced by buggy or experimental XZ encoders, bit-flipped bytes on damaged storage, or mistaking a similarly-named non-XZ file for an XZ stream.

Related errors


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