can1357/oh-my-pi · error · ArchiveError

LZH member '${memberPath}' failed CRC-16 verification

Error message

LZH member '${memberPath}' failed CRC-16 verification

What it means

Thrown by the LZH member extractor after decompression when the CRC-16 of the produced output does not match the CRC stored in the member's header. It means the archive bytes are corrupt, truncated, or the decompressor produced wrong output. The library verifies integrity before returning extracted data, so data is never silently wrong.

Source

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

				break;
			case "-lh6-":
				output = decompressLhStatic(packed, size, 1 << 15, 5, 16, "LZH -lh6-");
				break;
			case "-lh7-":
				output = decompressLhStatic(packed, size, 1 << 16, 5, 17, "LZH -lh7-");
				break;
			case "-lzs-":
				output = decompressLzs(packed, size);
				break;
			case "-lh1-":
				throw new ArchiveError(`LZH member '${memberPath}' uses unsupported dynamic-Huffman method -lh1-`);
			default:
				throw new ArchiveError(`LZH member '${memberPath}' uses unsupported compression method ${this.#method}`);
		}
		if (output.byteLength !== size)
			throw new ArchiveError(`LZH member '${memberPath}' extracted to an unexpected size`);
		if (crc16Arc(output) !== this.#crc)
			throw new ArchiveError(`LZH member '${memberPath}' failed CRC-16 verification`);
		return output;
	}
}

interface ParsedLzhHeader {
	method: string;
	packedSize: number;
	size: number;
	dataStart: number;
	nextOffset: number;
	crc: number;
	path?: string;
	mtimeMs?: number;
	mode?: number;
}

function parseLzhHeader(bytes: Uint8Array, offset: number, options: FormatReadOptions): ParsedLzhHeader {
	assertRange(bytes, offset, offset + 22, "header");

View on GitHub (pinned to 9690622007)

Solutions

  1. Re-download or re-extract the archive from a trusted source and verify its checksum
  2. Repack the archive with a conforming LHA tool (e.g. lha) to regenerate a correct CRC
  3. Confirm the source file is not being read truncated (check file size and read stream completion)
  4. If you control the writer, ensure it computes the standard ARC CRC-16 over the raw member data

Example fix

// before: blindly reusing a partially downloaded archive
const bytes = await partialRead(url);
const archive = LzhReader.read(bytes);
// after: verify completeness first
const bytes = new Uint8Array(await Bun.file(path).arrayBuffer());
if (bytes.byteLength < expectedSize) throw new Error('incomplete archive');
const archive = LzhReader.read(bytes);
Defensive patterns

Strategy: try-catch

Validate before calling

if (!(await Bun.file(path).exists())) throw new Error('archive missing');

Try / catch

try { extract(); } catch (err) { if (err instanceof ArchiveError) report(err.message); else throw err; }

Prevention

When it happens

Trigger: Calling the LZH reader's member-extraction API on an archive whose compressed payload was corrupted in transit or on disk, or a member whose header CRC field does not match the actual data (hand-edited or badly written archives).

Common situations: Downloads that were truncated or corrupted, archives stored on failing media, archives created by non-conforming LZH writers that compute CRC differently, or byte-level tampering.

Related errors


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