can1357/oh-my-pi · error · ArchiveError

Invalid LZH common extended header

Error message

Invalid LZH common extended header

What it means

LZH extended header type 0x00 carries a CRC-16 over the common header area and must be at least 2 bytes (one u16). When the parsed data section is shorter than 2 bytes the header is malformed, so processExtendedHeader throws.

Source

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

	unicodeFilename?: string;
	unicodeDirectory?: string;
	mtimeMs?: number;
	mode?: number;
	packedSize?: number;
	size?: number;
	commonCrc?: number;
	commonCrcOffset?: number;
}

function processExtendedHeader(
	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;
			}

View on GitHub (pinned to 9690622007)

Solutions

  1. Re-obtain the archive — a sub-2-byte 0x00 header means the size fields are corrupt
  2. Check the file size against the expected checksum; if truncated, re-transfer
  3. If you write LZH archives, ensure each extended header's size field covers type byte + data + 2-byte size trailer so parsing yields >= 2 data bytes for type 0x00
  4. Catch ArchiveError around archive reads and surface a per-file corruption message instead of failing the whole batch

Example fix

null
Defensive patterns

Strategy: try-catch

Type guard

null

Try / catch

try {
	const entries = await readArchive(lzhBytes);
} catch (err) {
	if (err instanceof ArchiveError && err.message.includes("common extended header")) {
		// header chain corrupt; surface per-file corruption instead of crashing
		return { status: "corrupt", reason: "lzh-common-header" };
	}
	throw err;
}

Prevention

When it happens

Trigger: Reading a level-1 or level-2 LZH member whose extended-header chain contains a type 0x00 entry with a data payload shorter than 2 bytes — caused by a wrong extension-size field, truncation, or a corrupt chain.

Common situations: Truncated downloads of .lzh files; archives edited by scripts that rewrote extended headers without fixing sizes; damaged floppy-era archives being recovered.

Related errors


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