can1357/oh-my-pi · error · ArchiveError
Unsupported LZH header level ${level}
Error message
Unsupported LZH header level ${level} What it means
Thrown when parsing an LZH header whose level byte (offset+20) is greater than 2. This library supports LHA header levels 0, 1, and 2 only; level 3 headers use a different structure entirely. The library refuses to guess at unknown formats rather than misparse bytes.
Source
Thrown at packages/utils/src/ar/lzh.ts:464
}
}
interface ParsedLzhHeader {
method: string;
packedSize: number;
size: number;
dataStart: number;
nextOffset: number;
crc: number;
path?: string;
mtimeMs?: number;
mode?: number;
}
function parseLzhHeader(bytes: Uint8Array, offset: number, options: FormatReadOptions): ParsedLzhHeader {
assertRange(bytes, offset, offset + 22, "header");
const level = bytes[offset + 20]!;
if (level > 2) throw new ArchiveError(`Unsupported LZH header level ${level}`);
const method = String.fromCharCode(...bytes.subarray(offset + 2, offset + 7));
if (!LHA_METHOD_PATTERN.test(method)) throw new ArchiveError(`Invalid LZH compression method '${method}'`);
let packedSize = u32(bytes, offset + 7);
let size = u32(bytes, offset + 11);
let crc = 0;
let legacyFilename: string | undefined;
let mtimeMs: number | undefined;
let osId = 0;
let dataStart: number;
const fields: LzhExtendedFields = {};
if (level < 2) {
const headerLength = bytes[offset]!;
const minimum = level === 0 ? 22 : 25;
if (headerLength < minimum) throw new ArchiveError(`Invalid LZH level-${level} header size`);
const baseEnd = offset + headerLength + 2;
assertRange(bytes, offset, baseEnd, "header");
let sum = 0;View on GitHub (pinned to 9690622007)
Solutions
- Convert the archive to a level-0/1/2 LHA file using lha or 7-Zip before reading
- Use a different extraction tool/library that supports LZH level-3 headers
- Verify the file is actually an LZH archive (check the -lh?- magic at offset 2)
Example fix
// before: feeding the raw file to the LZH reader
const archive = lzhRead(suspiciousBytes);
// after: probe the method signature first
const method = String.fromCharCode(...bytes.subarray(2, 7));
if (!/^-(lz|lh)[0-9a-z]-$/i.test(method)) throw new Error('not an LZH file');
const archive = lzhRead(bytes); Defensive patterns
Strategy: fallback
Validate before calling
if (!looksLikeLzh(bytes)) routeToOtherReader(bytes);
Type guard
function looksLikeLzh(b: Uint8Array): boolean { return /^-(lh|lz)[0-9a-z]-$/.test(String.fromCharCode(...b.subarray(2,7))); } Try / catch
try { return lzhRead(bytes); } catch (err) { if (err instanceof ArchiveError) return fallbackExtractor(bytes); throw err; } Prevention
- Route files by signature, not extension
- Convert legacy formats before ingestion
When it happens
Trigger: Reading an LHA file that uses level-3 headers (rare, produced by some UnLHA variants), or pointing the reader at a non-LZH file whose bytes coincidentally pass initial framing (e.g. magic check) but have a garbage level byte.
Common situations: Processing obscure archives generated by Japanese LHA tools using level-3 format, or accidentally passing a corrupted/mislabeled file (e.g. a ZIP renamed .lzh) to the LZH reader.
Related errors
- Invalid LZH compression method '${method}'
- Unsupported multi-volume CAB archive: split CFDATA block
- Invalid ${label} Huffman table: oversubscribed codes
- Invalid ${label} Huffman table: incomplete codes
- Invalid ${label} Huffman table: prefix collision
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/954d886915102c6b.
Report an issue: GitHub.