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
- 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.
- Do NOT bypass the check if the file is untrusted — a mismatch is the designed tamper signal.
- If you legitimately repacked the ASAR, regenerate it with the official asar tool so header hashes match member data.
- 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
- Never bypass or strip integrity entries on untrusted ASAR files — the mismatch is the tamper signal.
- Verify publisher whole-file checksums/signatures before parsing.
- Regenerate ASARs with the official asar tool after any legitimate edit so hashes stay in sync.
- Watch for post-packaging processes (AV, sync, minifiers) that rewrite member bytes.
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
- Invalid XZ stream: block SHA-256 mismatch
- Downloaded binary digest mismatch: expected ${options.expect
- Embedded addon size mismatch for ${filename}: expected ${fil
- Embedded addon archive missing: ${[...pending.keys()].join("
- ARJ member '${memberPath}' failed CRC32 verification
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/19a519269ffe0324.
Report an issue: GitHub.