can1357/oh-my-pi · error · ArchiveError
Invalid LZMA2 stream: trailing data
Error message
Invalid LZMA2 stream: trailing data
What it means
After decoding the final LZMA2 chunk (marked by an end marker in the chunk control byte), the decoder requires the input cursor to land exactly at the end of the input buffer. If pos !== bytes.byteLength, extra undecoded bytes follow the terminated stream, so the input is not a single well-formed LZMA2 stream.
Source
Thrown at packages/utils/src/ar/codecs/lzma.ts:431
let property = takeByte();
if (property >= 9 * 5 * 5) throw new ArchiveError("Invalid LZMA2 properties");
const lc = property % 9;
property = Math.floor(property / 9);
const lp = property % 5;
const pb = Math.floor(property / 5);
if (lc + lp > 4) throw new ArchiveError("Invalid LZMA2 literal properties");
decoder.setProperties(lc, lp, pb);
propertiesSet = true;
}
if (packSize > bytes.byteLength - pos || unpackSize > maxOutput - decoder.outputPos)
throw new ArchiveError("Invalid LZMA2 chunk size");
if (resetsDictionary) decoder.resetDictionary();
else if (resetsState) decoder.resetState();
decoder.decodeChunk(bytes.subarray(pos, pos + packSize), unpackSize);
pos += packSize;
needDictionaryReset = false;
}
if (pos !== bytes.byteLength) throw new ArchiveError("Invalid LZMA2 stream: trailing data");
return output.subarray(0, decoder.outputPos);
} catch (error) {
if (error instanceof ArchiveError) throw error;
throw new ArchiveError(`Invalid LZMA2 stream: ${error instanceof Error ? error.message : String(error)}`);
}
}
View on GitHub (pinned to 9690622007)
Solutions
- Trim trailing padding/zero bytes so the buffer ends exactly at the LZMA2 end marker.
- Split concatenated LZMA2 streams and decompress each separately.
- Extract the payload using the container's recorded stream length instead of reading a fixed block size.
- If the extra data is intentional, slice it off before calling the decompressor.
Example fix
// before: fixed 4096-byte read includes padding const buf = new Uint8Array(4096); lzmaDecompress(buf.subarray(0, bytesRead), max); // after: use exact stream length lzmaDecompress(buf.subarray(0, streamLength), max);
Defensive patterns
Strategy: try-catch
Validate before calling
if (bytes.length > 0 && bytes[bytes.length - 1] !== 0x00) {
// LZMA2 streams end with a 0x00 terminator control byte
throw new Error("Buffer does not end at an LZMA2 stream terminator");
} Try / catch
try {
return lzmaDecompress(bytes, maxOutput);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes("trailing data")) {
throw new Error("Extra bytes after LZMA2 end marker — split streams or trim padding", { cause: err });
}
throw err;
} Prevention
- Slice buffers to the exact recorded stream length instead of fixed block reads.
- Split concatenated LZMA2 streams before decoding.
- Strip container padding before passing the payload.
- Don't blindly append multiple compressed payloads into one buffer.
When it happens
Trigger: Calling lzmaDecompress on a buffer that contains an LZMA2 stream plus appended padding or an extra chunk after the terminating 0x00 control byte; concatenating multiple LZMA2 streams into one buffer and decoding them as one.
Common situations: Manually extracted .xz payload with trailing zero padding; concatenated archives; reading a fixed-size block from a file/stream that includes data beyond the stream end.
Related errors
- Invalid LZMA2 stream: ${error instanceof Error ? error.messa
- Invalid LZMA2 chunk size
- Invalid non-zero compress (.Z) padding
- Invalid RAR archive: ${reason}
- archive destination exists: ${destSession}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/e7dbfa230fa19551.
Report an issue: GitHub.