can1357/oh-my-pi · error · ArchiveError
Multi-volume LZH archives are unsupported
Error message
Multi-volume LZH archives are unsupported
What it means
Extended header type 0x39 marks a multi-volume (split/disk-spanning) LZH archive. This library reads single in-memory archives only and cannot resolve members continued across volumes, so it refuses the archive up front.
Source
Thrown at packages/utils/src/ar/lzh.ts:365
type: number,
data: Uint8Array,
absoluteDataOffset: number,
fields: LzhExtendedFields,
): void {
switch (type) {
case 0x00:
if (data.byteLength < 2) throw new ArchiveError("Invalid LZH common extended header");
fields.commonCrc = u16(data, 0);
fields.commonCrcOffset = absoluteDataOffset;
break;
case 0x01:
fields.filename = decodeLegacy(data);
break;
case 0x02:
fields.directory = decodeLegacy(data).replaceAll("ÿ", "/");
break;
case 0x39:
throw new ArchiveError("Multi-volume LZH archives are unsupported");
case 0x41:
if (data.byteLength >= 16) {
const low = u32(data, 8);
const high = u32(data, 12);
const filetime = low + high * 0x100000000;
if (Number.isSafeInteger(filetime)) fields.mtimeMs = filetime / 10_000 - 11_644_473_600_000;
}
break;
case 0x42:
if (data.byteLength < 16) throw new ArchiveError("Invalid LZH 64-bit size extended header");
fields.packedSize = u64(data, 0);
fields.size = u64(data, 8);
break;
case 0x44:
fields.unicodeFilename = decodeUtf16(data);
break;
case 0x45:
fields.unicodeDirectory = decodeUtf16(data).replaceAll("ÿ", "/");View on GitHub (pinned to 9690622007)
Solutions
- Supply all volumes of the set and rejoin/split-merge them into a single archive using a tool that supports multi-volume LHA (e.g. LHA/UNLHA32 on the original media) before loading
- Re-create the archive as a single-volume .lzh (or a different format like zip) with all members included
- If you only need specific members, extract them with an external multi-volume-aware tool first, then repack individually
- Detect volume numbering in your app (e.g. .lzh/.l00/.l01 suffixes) and prompt the user to merge before calling the reader
Example fix
null
Defensive patterns
Strategy: validation
Validate before calling
// Detect likely multi-volume LHA sets before calling the reader
import * as fs from "node:fs";
function looksLikeMultiVolumeSet(basePath: string): boolean {
return /\.l(?:zh|ha|[0-9]{2})$/i.test(basePath) &&
fs.existsSync(basePath.replace(/\.l(?:zh|ha)$/i, ".l00"));
} Type guard
null
Try / catch
try {
const entries = await readArchive(lzhBytes);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes("Multi-volume")) {
// prompt user to merge volumes with a multi-volume-aware tool first
}
throw err;
} Prevention
- Keep multi-volume sets together and merge them before ingesting
- Convert legacy split archives to single-volume zip/lzh during archival migration
- Detect numbered volume suffixes (.l00, .l01) in file intake logic
When it happens
Trigger: Reading a .lzh file that is one part of a multi-disk/multi-volume set created with disk spanning (e.g. old backup sets spanning floppies or numbered .lzh/.l00/.l01 files).
Common situations: Recovering legacy backup archives split across disks; users supplying only the first volume of a set; archival migration of multi-part LHA files.
Related errors
- Multi-volume ARJ archives are unsupported
- Multi-volume ARJ members are unsupported
- Unsupported multi-volume CAB archive (previous/next cabinet
- Unsupported multi-volume RAR4 archive
- ARJ member '${memberPath}' uses unsupported compression meth
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/67409614ac32ddcf.
Report an issue: GitHub.