can1357/oh-my-pi · error · ArchiveError
Invalid XZ stream: truncated stream framing
Error message
Invalid XZ stream: truncated stream framing
What it means
After stripping trailing zero padding, discoverStreams() requires at least 24 bytes remaining — the minimum for a 12-byte stream header plus a 12-byte stream footer. A shorter remainder means the stream framing is cut off mid-structure, so the library refuses to parse it rather than produce garbage.
Source
Thrown at packages/utils/src/ar/codecs/xz.ts:117
}
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) {
blocksSize += Math.ceil(record.unpaddedSize / 4) * 4;View on GitHub (pinned to 9690622007)
Solutions
- Verify file size matches the expected .xz size and re-download/re-copy if truncated
- Check that the source transfer completed (checksum the file)
- If slicing a buffer manually, include at least the full 24-byte header+footer framing
- Only strip padding you know belongs between streams; keep whole streams intact
Example fix
// before
const bytes = buf.subarray(0, 20); // truncated
await xzDecode(bytes);
// after
if (buf.byteLength < 24) throw new Error("xz buffer too small (<24 bytes)");
const bytes = buf;
await xzDecode(bytes); Defensive patterns
Strategy: validation
Validate before calling
if (bytes.byteLength < 24) throw new Error(`xz input too small: ${bytes.byteLength} bytes (min 24)`); Type guard
null
Try / catch
try {
await xzDecode(bytes);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes("truncated stream framing")) {
throw new Error("XZ file is truncated or incomplete");
}
throw err;
} Prevention
- Verify downloaded file sizes against expected sizes
- Use checksums to confirm complete transfers
- Avoid reading files while a producer is still writing them
When it happens
Trigger: Passing a buffer whose non-padding tail is shorter than 24 bytes — e.g. a truncated .xz download, a partial read, or a slice that ends mid-footer. Also happens when concatenation handling drops the leading stream's header.
Common situations: Interrupted file transfers, HTTP range requests that fetched only part of the file, copying a file while it was still being written, or incorrectly slicing multi-stream xz buffers.
Related errors
- Invalid XZ stream: missing block header
- Invalid XZ stream: truncated block header
- Invalid XZ stream: truncated filter properties
- Invalid XZ stream: truncated block data
- Invalid LZMA2 chunk size
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/3c07ec3de9f47bb3.
Report an issue: GitHub.