can1357/oh-my-pi · error · ArchiveError
Unsupported XZ terminal filter ID 0x${last.id.toString(16)}
Error message
Unsupported XZ terminal filter ID 0x${last.id.toString(16)} (LZMA2 required) What it means
Every XZ block's filter chain must terminate in an LZMA2 filter (ID 0x21) with exactly one property byte (the dictionary size). The block declares some other terminal filter (e.g. Delta 0x03 or a BCJ filter as the last filter) or wrong property size, which this decoder does not support as a terminal coder.
Source
Thrown at packages/utils/src/ar/codecs/xz.ts:468
}
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");
if (declaredCompressed !== undefined && declaredCompressed !== compressedSize)
throw new ArchiveError("Invalid XZ stream: block compressed size mismatch");
if (declaredUncompressed !== undefined && declaredUncompressed !== record.uncompressedSize)
throw new ArchiveError("Invalid XZ stream: block uncompressed size mismatch");
const compressedStart = offset + headerSize;
const compressedEnd = compressedStart + compressedSize;
const paddingSize = (4 - ((headerSize + compressedSize) & 3)) & 3;
const checkStart = compressedEnd + paddingSize;
if (checkStart + integritySize > bytes.byteLength) throw new ArchiveError("Invalid XZ stream: truncated block data");
const last = filters[filters.length - 1]!;
if (last.id !== 0x21 || last.properties.byteLength !== 1)
throw new ArchiveError(`Unsupported XZ terminal filter ID 0x${last.id.toString(16)} (LZMA2 required)`);
let output = await lzma2Decompress(
last.properties[0]!,
bytes.subarray(compressedStart, compressedEnd),
record.uncompressedSize,
);
if (output.byteLength !== record.uncompressedSize)
throw new ArchiveError("Invalid XZ stream: decoded block size mismatch");
output = output.slice();
for (let index = filters.length - 2; index >= 0; index--) applyFilter(output, filters[index]!);
for (let index = compressedEnd; index < checkStart; index++)
if (bytes[index] !== 0) throw new ArchiveError("Invalid XZ stream: non-zero block padding");
verifyCheck(checkId, output, bytes.subarray(checkStart, checkStart + integritySize));
const paddedEnd = offset + Math.ceil(record.unpaddedSize / 4) * 4;
if (checkStart + integritySize !== paddedEnd)
throw new ArchiveError("Invalid XZ stream: block size does not match its index record");
return output;
}
View on GitHub (pinned to 9690622007)
Solutions
- Re-compress the archive with plain `xz -6` (default LZMA2-only chain) so the terminal filter is LZMA2.
- Check your encoder's filter ordering — XZ requires LZMA2 last in the chain.
- If you need arbitrary filter chains, use a full XZ implementation instead of this decoder.
- Verify the file is genuinely an XZ stream (magic 0xFD '7zXZ' 0x00) and not a renamed archive.
Example fix
// before $`custom-xz-encoder --filters delta,lzma2 --out archive.xz data.tar` // non-terminal misordering // after $`xz -6 -k -c data.tar > archive.xz` // standard LZMA2-only stream
Defensive patterns
Strategy: fallback
Validate before calling
if (!isXz(bytes)) throw new Error('Not an XZ stream');
// Non-standard filter chains cannot be detected cheaply up front; probe with the external tool if available.
const ok = await $`xz -t ${path}`.quiet().nothrow();
if (ok.exitCode !== 0) throw new Error('Unsupported or invalid XZ filter chain'); Try / catch
try {
return await xzDecompress(bytes, maxOutput);
} catch (err) {
if (err instanceof ArchiveError && /Unsupported XZ terminal filter/i.test(err.message)) {
// fall back to the system xz binary, which supports full filter chains
const res = await $`xz -dc ${path}`.quiet().nothrow();
if (res.exitCode === 0) return new Uint8Array(await res.arrayBuffer());
}
throw err;
} Prevention
- Produce archives with default `xz` settings (LZMA2-only chains).
- Document filter-chain restrictions for any custom encoder used in your pipeline.
- Detect exotic filter chains at ingest and re-encode once, up front.
- Keep a system xz fallback for archives this decoder rejects.
When it happens
Trigger: xzDecompress parses a block whose last filter id !== 0x21, or whose LZMA2 filter does not carry exactly 1 property byte.
Common situations: Archives compressed with filter chains this minimal decoder does not support (e.g. delta+LZMA2 chains misordered by a custom encoder), or files not actually produced by xz.
Related errors
- Unsupported XZ filter ID 0x${filter.id.toString(16)}
- ARJ member '${memberPath}' uses unsupported compression meth
- Encrypted ARJ archives are unsupported
- Multi-volume ARJ archives are unsupported
- Encrypted ARJ members are unsupported
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/f67183a1369f51ac.
Report an issue: GitHub.