can1357/oh-my-pi · error · ArchiveError

LZH uses the incompatible LHARK -lh7- variant

Error message

LZH uses the incompatible LHARK -lh7- variant

What it means

LHARK is an unofficial LZH variant that reuses the -lh7- method with level-1 headers and OS id 0x20 (MS-DOS) but changes the compression algorithm's tables. It is not decodable by this library, so it is detected and rejected up front instead of producing garbage output.

Source

Thrown at packages/utils/src/ar/lzh.ts:561

				break;
			}
			if (extensionSize < 3 || cursor + extensionSize > headerEnd)
				throw new ArchiveError("Invalid LZH extended header size");
			if (++extensionCount > 65_535) throw new ArchiveError("Invalid LZH archive: too many extended headers");
			const type = bytes[cursor + 2]!;
			const data = bytes.subarray(cursor + 3, cursor + extensionSize);
			if (type === 0x01 || type === 0x02 || type === 0x44 || type === 0x45) {
				assertArchivePathBytes(data.byteLength, "member path", options.limits.maxPathBytes);
			}
			processExtendedHeader(type, data, cursor + 3, fields);
			cursor += extensionSize;
		}
		if (cursor !== headerEnd) throw new ArchiveError("Invalid LZH level-2 extended header chain");
		dataStart = headerEnd;
		packedSize = fields.packedSize ?? packedSize;
	}
	if (level === 1 && osId === 0x20 && method === "-lh7-") {
		throw new ArchiveError("LZH uses the incompatible LHARK -lh7- variant");
	}

	size = fields.size ?? size;
	mtimeMs = fields.mtimeMs ?? mtimeMs;
	const mode = fields.mode;
	if (fields.commonCrc !== undefined) {
		const relative = fields.commonCrcOffset! - offset;
		if (crc16WithZeroRange(bytes.subarray(offset, dataStart), relative, relative + 2) !== fields.commonCrc) {
			throw new ArchiveError("Invalid LZH common header CRC-16");
		}
	}
	const filename = fields.unicodeFilename ?? fields.filename ?? legacyFilename ?? "";
	const directory = fields.unicodeDirectory ?? fields.directory ?? "";
	const rawPath = `${directory}${directory && !/[\\/]$/.test(directory) ? "/" : ""}${filename}`;
	assertArchivePathString(rawPath, "member path", options.limits.maxPathBytes);
	assertArchiveMemberSize(size, rawPath || "<unnamed>", options.limits);
	assertRange(bytes, dataStart, dataStart + packedSize, "member data");
	return {

View on GitHub (pinned to 9690622007)

Solutions

  1. Identify the file as LHARK-created; use a tool that supports LHARK (e.g. the original LHARK under DOS emulation) to extract it.
  2. Re-compress the contents with a standard LHA tool (-lh5-/-lh6-/-lh7- from LHA/lhasa) and use the new archive.
  3. If you only need the contents, extract externally and feed individual files to your pipeline instead.
  4. Catch ArchiveError with this message and surface a clear 'LHARK variant unsupported' notice to end users.

Example fix

// before
const entries = await readLzh(source, options);
// after
try {
  const entries = await readLzh(source, options);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes("LHARK")) {
    throw new Error("This is a LHARK archive; convert it with a standard LHA tool first");
  }
  throw err;
}
Defensive patterns

Strategy: fallback

Validate before calling

// detect the LHARK signature before reading
const bytes = await readAllBytes(source);
const method = String.fromCharCode(bytes[2], bytes[3], bytes[4], bytes[5], bytes[6]);
if (method === "-lh7-" && bytes[20] === 1) {
  throw new Error("LHARK variant detected — convert with an LHARK-aware tool first");
}

Try / catch

try {
  const entries = await readLzh(source, options);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes("LHARK")) {
    return extractLharkExternally(path); // fallback path
  }
  throw err;
}

Prevention

When it happens

Trigger: readLzh() on a level-1 header with osId 0x20 and compression method -lh7-.

Common situations: Archives created by the LHARK archiver (rare, mostly from Japanese/DOS-era sources) mislabeled as standard LHA; users confusing LHARK files with regular .lzh files.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/11817d1cf46ae51a. Report an issue: GitHub.