can1357/oh-my-pi · error · ArchiveError

Invalid LZH Unix timestamp extended header

Error message

Invalid LZH Unix timestamp extended header

What it means

Extended header type 0x54 stores a Unix mtime as a u32 seconds value and must be at least 4 bytes long. A shorter data section is malformed, so the reader throws instead of producing a bogus timestamp.

Source

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

			}
			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;
		this.#start = start;
		this.#packedSize = packedSize;
		this.#method = method;
		this.#crc = crc;

View on GitHub (pinned to 9690622007)

Solutions

  1. Re-transfer the archive — the extended-header chain is corrupt
  2. Cross-check with an external extractor to locate the damaged member; repack the archive dropping bad headers
  3. If you write LZH archives, emit type 0x54 headers with exactly 4 bytes (u32 LE epoch seconds) plus the 2-byte size trailer
  4. Catch ArchiveError per member and continue processing other members where your API surface allows

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 timestamp extended header")) {
		// proceed without mtime or re-acquire the archive
	}
	throw err;
}

Prevention

When it happens

Trigger: Reading an LZH member whose extended-header chain contains a type 0x54 entry with fewer than 4 data bytes — corrupt extension-size fields, truncation, or a non-conformant writer.

Common situations: Unix-origin .lzh archives with damaged headers; downloads cut short; archives processed by lossy metadata-editing tools.

Related errors


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