can1357/oh-my-pi · error · ArchiveError
Invalid XZ BCJ filter 0x${filter.id.toString(16)} start offs
Error message
Invalid XZ BCJ filter 0x${filter.id.toString(16)} start offset What it means
Each BCJ XZ filter requires its start offset to be aligned to the instruction size it decodes (16 for ARM64, 2 for RISC-V/Thumb-style, 4 for most others, 1 for x86's special case here when id=4 alignment is 1). The library throws when the 4-byte start offset stored in a BCJ filter's properties is not a multiple of the filter's required alignment.
Source
Thrown at packages/utils/src/ar/codecs/xz.ts:380
}
write32LE(bytes, index, instruction);
write32LE(bytes, index + 4, instruction2);
index += 6;
}
}
function applyFilter(bytes: Uint8Array, filter: XzFilter): void {
if (filter.id === 3) {
if (filter.properties.byteLength !== 1) throw new ArchiveError("Invalid XZ Delta filter properties");
deltaDecode(bytes, filter.properties[0]! + 1);
return;
}
if (filter.properties.byteLength !== 0 && filter.properties.byteLength !== 4)
throw new ArchiveError(`Invalid XZ BCJ filter 0x${filter.id.toString(16)} properties`);
const startOffset = filter.properties.byteLength === 4 ? read32LE(filter.properties, 0) : 0;
const alignment = filter.id === 6 ? 16 : filter.id === 8 || filter.id === 11 ? 2 : filter.id === 4 ? 1 : 4;
if ((startOffset & (alignment - 1)) !== 0)
throw new ArchiveError(`Invalid XZ BCJ filter 0x${filter.id.toString(16)} start offset`);
switch (filter.id) {
case 4:
x86Decode(bytes, startOffset);
break;
case 5:
powerPcDecode(bytes, startOffset);
break;
case 6:
ia64Decode(bytes, startOffset);
break;
case 7:
armDecode(bytes, startOffset);
break;
case 8:
armThumbDecode(bytes, startOffset);
break;
case 9:
sparcDecode(bytes, startOffset);View on GitHub (pinned to 9690622007)
Solutions
- Re-compress the file with standard xz using default BCJ settings (no custom --delta start offset) to get an aligned start offset
- Check the producing encoder's start-offset argument and align it to the filter's instruction size
- Verify the file with `xz -t` and obtain a good copy if the bytes are corrupt
- If this file must be decoded, pre-process it externally (decode with the xz binary) and feed uncompressed data to the library
Example fix
// before: unaligned start offset for PowerPC BCJ (alignment 4)
const filter = { id: 5, properties: new Uint8Array([1, 0, 0, 0]) };
// after: start offset aligned to the filter's instruction size
const filter = { id: 5, properties: new Uint8Array([4, 0, 0, 0]) }; Defensive patterns
Strategy: validation
Validate before calling
function bcjStartOffsetAligned(f: { id: number; properties: Uint8Array }): boolean {
if (f.properties.byteLength !== 4) return true;
const off = f.properties[0] | f.properties[1] << 8 | f.properties[2] << 16 | f.properties[3] << 24;
const align = f.id === 6 ? 16 : f.id === 8 || f.id === 11 ? 2 : f.id === 4 ? 1 : 4;
return (off & (align - 1)) === 0;
} Type guard
null
Try / catch
try {
await decodeXz(bytes);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes('start offset')) {
throw new Error('Archive BCJ start offset is misaligned; re-compress with default xz settings');
}
throw err;
} Prevention
- When compressing with BCJ filters, leave start offsets at defaults or align them to the filter's instruction size
- Avoid custom xz encoder flags (e.g. --delta=start=...) unless you control both ends
- Keep the xz tool and this library current so exotic configurations are handled consistently
When it happens
Trigger: Decompressing an XZ stream where a BCJ filter's properties contain a 4-byte start offset whose value fails the alignment check (e.g. start offset 1 with a 4-byte-aligned filter such as PowerPC or SPARC).
Common situations: Archives produced by encoders that wrote an unaligned start offset; manual or corrupted edits to filter properties; exotic BCJ start offsets from non-default encoder configurations that this decoder validates strictly.
Related errors
- Invalid XZ BCJ filter 0x${filter.id.toString(16)} properties
- Invalid XZ stream: padding without a stream
- Invalid XZ stream: footer magic mismatch
- Invalid XZ stream: footer CRC32 mismatch
- Invalid XZ stream: backward index size is invalid
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/c3150a70b258ab83.
Report an issue: GitHub.