can1357/oh-my-pi · error · ArchiveError
Invalid LZH archive: truncated ${what}
Error message
Invalid LZH archive: truncated ${what} What it means
assertRange validates that a [start,end) byte range for a header field (name, method, size, CRC, etc. named by `what`) lies fully inside the buffer. Any non-integer, negative, reversed, or out-of-bounds range means the archive is truncated, so parsing aborts with a message naming the field.
Source
Thrown at packages/utils/src/ar/lzh.ts:304
function u32(bytes: Uint8Array, offset: number): number {
return (bytes[offset]! | (bytes[offset + 1]! << 8) | (bytes[offset + 2]! << 16) | (bytes[offset + 3]! << 24)) >>> 0;
}
function u64(bytes: Uint8Array, offset: number): number {
const value = u32(bytes, offset) + u32(bytes, offset + 4) * 0x100000000;
if (!Number.isSafeInteger(value)) throw new ArchiveError("LZH uses sizes too large to read safely");
return value;
}
function assertRange(bytes: Uint8Array, start: number, end: number, what: string): void {
if (
!Number.isSafeInteger(start) ||
!Number.isSafeInteger(end) ||
start < 0 ||
end < start ||
end > bytes.byteLength
) {
throw new ArchiveError(`Invalid LZH archive: truncated ${what}`);
}
}
function decodeLegacy(bytes: Uint8Array): string {
let end = bytes.indexOf(0);
if (end < 0) end = bytes.byteLength;
return LEGACY_DECODER.decode(bytes.subarray(0, end));
}
function decodeUtf16(bytes: Uint8Array): string {
if ((bytes.byteLength & 1) !== 0) throw new ArchiveError("Invalid LZH Unicode path header: odd UTF-16 length");
let end = bytes.byteLength;
while (end >= 2 && bytes[end - 1] === 0 && bytes[end - 2] === 0) end -= 2;
return UTF16LE_DECODER.decode(bytes.subarray(0, end));
}
function dosTimeToMs(value: number): number | undefined {
if (value === 0) return undefined;View on GitHub (pinned to 9690622007)
Solutions
- Check file size and re-download/re-copy the complete archive
- Validate the archive container before extracting (CRC / archive-level integrity)
- Ensure earlier header size reads (including extended headers) use the right widths/offsets
- Catch ArchiveError and report the entry as truncated
Example fix
// before
const header = new Uint8Array(packed.buffer, 0, 21); // may exceed packed.length
const entry = parseLzhHeader(header);
// after
const header = packed.subarray(0, Math.min(21, packed.length));
if (packed.length < 21) throw new Error("file truncated before header");
const entry = parseLzhHeader(header); Defensive patterns
Strategy: validation
Validate before calling
function isTruncated(file: Uint8Array, needed: number): boolean {
return file.length < needed;
}
if (isTruncated(packed, 21)) throw new Error("file truncated before LZH header"); Type guard
function hasBytes(buf: Uint8Array, start: number, end: number): boolean {
return Number.isSafeInteger(start) && Number.isSafeInteger(end) &&
start >= 0 && end >= start && end <= buf.byteLength;
} Try / catch
try {
const entry = parseLzhHeader(packed.subarray(offset));
} catch (err) {
if (err instanceof ArchiveError && err.message.includes("truncated")) {
return { ok: false, reason: "truncated archive" };
}
throw err;
} Prevention
- Check file size against expected length before parsing
- Re-download or re-copy incomplete files
- Validate archive-level integrity before member extraction
- Never trust computed offsets from previously parsed (possibly corrupt) size fields
When it happens
Trigger: parseLzhHeader on a buffer shorter than the header claims — truncated download, partial file, or a computed end offset past byteLength because a prior size field was misread.
Common situations: Interrupted uploads/downloads; reading an LZH member from a truncated container; misparsed size fields inflating header offsets; fuzzed inputs.
Related errors
- Invalid ${label} Huffman table: oversubscribed codes
- Invalid ${label} Huffman table: incomplete codes
- Invalid ${label} temporary Huffman table
- Invalid LZH compression method '${method}'
- Invalid LZH filename length
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/35b9905f7b10627e.
Report an issue: GitHub.