can1357/oh-my-pi · error · ArchiveError

Invalid XZ stream: padding without a stream

Error message

Invalid XZ stream: padding without a stream

What it means

discoverStreams() walks the buffer backwards from the end, peeling off 4-byte-aligned zero padding between concatenated XZ streams before parsing each stream footer. If the zero-padding strip consumes the entire buffer, there is no stream left to parse — the input is all zeros (or ends in zeros with nothing before them). The library throws ArchiveError to signal the byte buffer is not a decodable XZ container.

Source

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

		records.push({ unpaddedSize, uncompressedSize });
	}
	while (cursor.pos < cursor.limit)
		if (bytes[cursor.pos++] !== 0) throw new ArchiveError("Invalid XZ stream: non-zero index padding");
	return records;
}

function discoverStreams(bytes: Uint8Array): XzStream[] {
	if (bytes.byteLength === 0 || (bytes.byteLength & 3) !== 0)
		throw new ArchiveError("Invalid XZ stream: size is not a multiple of four bytes");
	const streams: XzStream[] = [];
	let end = bytes.byteLength;
	while (end > 0) {
		let padding = 0;
		while (end >= 4 && bytes[end - 1] === 0 && bytes[end - 2] === 0 && bytes[end - 3] === 0 && bytes[end - 4] === 0) {
			end -= 4;
			padding += 4;
		}
		if (end === 0) throw new ArchiveError("Invalid XZ stream: padding without a stream");
		if (end < 24) throw new ArchiveError("Invalid XZ stream: truncated stream framing");
		const footerStart = end - 12;
		if (bytes[footerStart + 10] !== 0x59 || bytes[footerStart + 11] !== 0x5a)
			throw new ArchiveError("Invalid XZ stream: footer magic mismatch");
		if (crc32(bytes.subarray(footerStart + 4, footerStart + 10)) !== read32LE(bytes, footerStart))
			throw new ArchiveError("Invalid XZ stream: footer CRC32 mismatch");
		const flag0 = bytes[footerStart + 8]!;
		const flag1 = bytes[footerStart + 9]!;
		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) {

View on GitHub (pinned to 9690622007)

Solutions

  1. Verify the buffer starts with the XZ magic bytes fd 37 7a 58 5a 00 before decoding
  2. Check the file is a complete, non-empty .xz file (re-download or re-compress)
  3. Confirm you are slicing the correct byte range of a multi-stream archive
  4. If handling concatenated streams yourself, ensure each stream's full bytes are included

Example fix

// before
const bytes = new Uint8Array(await Bun.file(path).arrayBuffer()).subarray(wrongOffset);
await xzDecode(bytes); // all-zero slice -> throws
// after
const bytes = new Uint8Array(await Bun.file(path).arrayBuffer());
if (!equalBytes(bytes.subarray(0, 6), Uint8Array.of(0xfd,0x37,0x7a,0x58,0x5a,0x00))) throw new Error("not an xz file");
await xzDecode(bytes);
Defensive patterns

Strategy: validation

Validate before calling

function looksLikeXz(bytes: Uint8Array): boolean {
  const magic = Uint8Array.of(0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00);
  if (bytes.byteLength < 24 || bytes.byteLength % 4 !== 0) return false;
  return magic.every((b, i) => bytes[i] === b) || bytes.some((b) => b !== 0);
}

Type guard

null

Try / catch

try {
  const out = await xzDecode(bytes);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes("padding without a stream")) {
    throw new Error("Input is not an XZ stream (all padding/empty)");
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling the xz codec (via streams()/discoverStreams) with a buffer consisting entirely of zero bytes, or a concatenated-streams buffer whose trailing zero padding runs back to offset 0 with no stream footer preceding it. Also triggered by a truncated file where only padding bytes survived.

Common situations: Reading an empty/zero-filled .xz file (e.g. sparse file, failed download writing zeros), passing the wrong buffer offset/length so only a padding region is handed to the decoder, or corruption that zeroed the stream data.

Related errors


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