can1357/oh-my-pi · critical · ArchiveError

ASAR member '${formatArchivePathForError(memberPath)}' faile

Error message

ASAR member '${formatArchivePathForError(memberPath)}' failed SHA256 integrity verification

What it means

ASAR archives embed a SHA256 hash for each member in the header's integrity block. After reading a member's bytes, verifyIntegrity recomputes the hash with Bun.CryptoHasher and compares it to the recorded hash. A mismatch means the member bytes differ from what was packed — corruption, tampering, or an out-of-sync header — so the read is aborted.

Source

Thrown at packages/utils/src/ar/asar.ts:96

		throw invalidAsar(`file '${label}' has invalid integrity blocks`);
	}
	const expectedBlocks = Math.max(1, Math.ceil(size / value.blockSize));
	if (value.blocks.length !== expectedBlocks) {
		throw invalidAsar(`file '${label}' has an inconsistent integrity block count`);
	}
	for (const block of value.blocks) {
		if (typeof block !== "string" || !SHA256_HEX.test(block)) {
			throw invalidAsar(`file '${label}' has an invalid integrity block hash`);
		}
	}
	return { algorithm: "SHA256", hash: value.hash.toLowerCase() };
}

function verifyIntegrity(bytes: Uint8Array, integrity: AsarIntegrity | undefined, memberPath: string): void {
	if (!integrity) return;
	const actual = new Bun.CryptoHasher("sha256").update(bytes).digest("hex");
	if (actual !== integrity.hash) {
		throw new ArchiveError(
			`ASAR member '${formatArchivePathForError(memberPath)}' failed SHA256 integrity verification`,
		);
	}
}

class PackedAsarMemberSource implements MemberSource {
	readonly #source: ByteSource;
	readonly #offset: number;
	readonly #size: number;
	readonly #integrity?: AsarIntegrity;

	constructor(source: ByteSource, offset: number, size: number, integrity: AsarIntegrity | undefined) {
		this.#source = source;
		this.#offset = offset;
		this.#size = size;
		this.#integrity = integrity;
	}

View on GitHub (pinned to 9690622007)

Solutions

  1. Re-obtain the ASAR file from a trusted source and verify the whole-file checksum first; integrity failure usually means the file itself is bad.
  2. Do NOT bypass the check if the file is untrusted — a mismatch is the designed tamper signal.
  3. If you legitimately repacked the ASAR, regenerate it with the official asar tool so header hashes match member data.
  4. Confirm no post-processing step (minifier, antivirus quarantine/restore, sync tool) is rewriting member bytes after packaging.

Example fix

// before
const bytes = await member.read(size, path); // throws on hash mismatch
// after
try {
  const bytes = await member.read(size, path);
} catch (e) {
  if (e instanceof ArchiveError && e.message.includes("integrity verification")) {
    const fresh = await reDownloadTrustedAsar(url);
    return readMember(fresh, path);
  }
  throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify the whole ASAR file against a publisher-provided checksum before any member read.
const whole = createHash("sha256").update(asarBytes).digest("hex");
if (expectedFileSha256 && whole !== expectedFileSha256) {
	throw new Error("ASAR file does not match publisher checksum; refusing to read");
}

Type guard

function hasIntegrityEntry(entry: AsarHeaderEntry): entry is AsarHeaderEntry & { integrity: AsarIntegrity } {
	return typeof (entry as { integrity?: unknown }).integrity === "object" && entry.integrity !== null && typeof entry.integrity.hash === "string";
}

Try / catch

try {
	const bytes = await member.read(size, path);
} catch (e) {
	if (e instanceof ArchiveError && e.message.includes("failed SHA256 integrity verification")) {
		// tamper/corruption signal: quarantine the file, do not retry in place
		await quarantine(asarPath);
		throw new SecurityError(`ASAR tampering detected in ${path}`);
	}
	throw e;
}

Prevention

When it happens

Trigger: The ASAR read path (member read → verifyIntegrity) computes sha256 of the extracted bytes and it does not equal the integrity.hash recorded in the ASAR header for that memberPath. Only fires when the header actually carries an integrity entry (no integrity → check skipped).

Common situations: ASAR file modified after signing (manual edits, patchers, malware); truncated or bit-rotted files; a repacked header paired with stale member data; MITM/corrupted downloads of Electron app resources.

Related errors


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