can1357/oh-my-pi · error · ArchiveError

Invalid XZ stream: backward index size is invalid

Error message

Invalid XZ stream: backward index size is invalid

What it means

The footer's backward-size field encodes the size of the stream index as (stored+1)*4 bytes. discoverStreams() validates this is a safe integer and that the index actually fits before the footer; a stored size that overflows or points before the stream start means the footer is corrupt or the buffer is not a real XZ stream.

Source

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

		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) {
			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;

View on GitHub (pinned to 9690622007)

Solutions

  1. Verify the file integrity (xz -t or checksum) and re-acquire it if corrupt
  2. Re-compress the data to regenerate a consistent footer/index
  3. If slicing buffers, confirm the footer offset is exactly end-12 for the stream
  4. Reject untrusted archives up front if you know they come from an unreliable source

Example fix

// before
const slice = whole.subarray(whole.byteLength - 10); // shifts footer fields
await xzDecode(slice); // bogus backward size
// after
const slice = whole; // parse full streams, library locates the footer itself
await xzDecode(slice);
Defensive patterns

Strategy: validation

Validate before calling

if (bytes.byteLength % 4 !== 0 || bytes.byteLength < 24) throw new Error("not plausibly an xz buffer");

Type guard

null

Try / catch

try {
  await xzDecode(bytes);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes("backward index size")) {
    throw new Error("XZ index/footer inconsistent — archive is corrupt or malformed");
  }
  throw err;
}

Prevention

When it happens

Trigger: A backward-size field (footerStart+4..7) corrupted to an implausible value, a misaligned buffer slice so garbage is read as the size, or a deliberately malformed file whose declared index is larger than the preceding bytes.

Common situations: Corrupted downloads, fuzzed/malformed archives, or hand-assembled XZ streams with an incorrect index size encoding.

Related errors


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