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
- Verify the buffer starts with the XZ magic bytes fd 37 7a 58 5a 00 before decoding
- Check the file is a complete, non-empty .xz file (re-download or re-compress)
- Confirm you are slicing the correct byte range of a multi-stream archive
- 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
- Check the XZ magic bytes before decoding
- Ensure files are fully transferred and non-empty
- Don't hand slices of multi-stream buffers to the decoder; pass whole buffers
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
- Invalid XZ stream: backward index size is invalid
- Invalid XZ Delta filter properties
- Invalid XZ BCJ filter 0x${filter.id.toString(16)} properties
- Invalid XZ stream: footer magic mismatch
- Invalid XZ stream: footer CRC32 mismatch
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/a3ad5116f0ad72af.
Report an issue: GitHub.