can1357/oh-my-pi · error · ArchiveError

Invalid LZH Unix permissions extended header

Error message

Invalid LZH Unix permissions extended header

What it means

Extended header type 0x50 stores Unix permission bits as a u16 and must be at least 2 bytes long. A shorter payload means the header chain is malformed, so the reader throws rather than guessing a mode.

Source

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

				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("ÿ", "/");
			break;
		case 0x50:
			if (data.byteLength < 2) throw new ArchiveError("Invalid LZH Unix permissions extended header");
			fields.mode = u16(data, 0);
			break;
		case 0x54:
			if (data.byteLength < 4) throw new ArchiveError("Invalid LZH Unix timestamp extended header");
			fields.mtimeMs = u32(data, 0) * 1000;
			break;
	}
}

class LzhMemberSource implements MemberSource {
	readonly #archive: Uint8Array;
	readonly #start: number;
	readonly #packedSize: number;
	readonly #method: string;
	readonly #crc: number;

	constructor(archive: Uint8Array, start: number, packedSize: number, method: string, crc: number) {
		this.#archive = archive;

View on GitHub (pinned to 9690622007)

Solutions

  1. Re-obtain the archive — the header size chain is corrupt
  2. Verify with an external tool (7-Zip, lha) which member's headers are damaged and repair/skip it
  3. If you write LZH archives, ensure type 0x50 headers carry exactly 2 bytes (u16 LE mode) plus the size trailer
  4. Treat missing permission info gracefully in your app by catching ArchiveError and defaulting modes

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("Unix permissions extended header")) {
		// fall back to default modes or re-acquire the archive
	}
	throw err;
}

Prevention

When it happens

Trigger: Reading an LZH level-1/2 member whose extended-header chain contains a type 0x50 entry with fewer than 2 data bytes — corrupt size field, truncation, or a buggy writer.

Common situations: Unix-created .lzh archives (LHA for Linux, lhasa) with damaged headers; archives whose extended headers were rewritten by scripts; partially recovered files.

Related errors


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