can1357/oh-my-pi · error · ArchiveError

Unpacked ASAR file '${label}' size differs from its archive

Error message

Unpacked ASAR file '${label}' size differs from its archive header (${stat.size} != ${this.#size} bytes)

What it means

Thrown when the unpacked sidecar file exists and is a regular file, but its size on disk differs from the `size` recorded for that member in the ASAR header. The archive format relies on the header being authoritative, so the mismatch makes the payload untrustworthy.

Source

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

	}

	async read(size: number, memberPath: string): Promise<Uint8Array> {
		const label = formatArchivePathForError(memberPath);
		if (size !== this.#size) {
			throw new ArchiveError(`ASAR member '${label}' has an inconsistent size`);
		}
		if (!this.#filePath) {
			throw new ArchiveError(`Archive file '${label}' is unpacked and requires a filesystem-backed ASAR archive`);
		}
		const file = Bun.file(this.#filePath);
		const stat = await file.stat().catch(() => {
			throw new ArchiveError(`Unpacked ASAR file '${label}' was not found`);
		});
		if (stat.isDirectory()) {
			throw new ArchiveError(`Unpacked ASAR file '${label}' is a directory`);
		}
		if (stat.size !== this.#size) {
			throw new ArchiveError(
				`Unpacked ASAR file '${label}' size differs from its archive header (${stat.size} != ${this.#size} bytes)`,
			);
		}
		let bytes: Uint8Array;
		try {
			bytes = await file.bytes();
		} catch (error) {
			throw new ArchiveError(`Failed to read unpacked ASAR file '${label}': ${describeError(error)}`);
		}
		if (bytes.byteLength !== this.#size) {
			throw new ArchiveError(`Unpacked ASAR file '${label}' changed while being read`);
		}
		verifyIntegrity(bytes, this.#integrity, memberPath);
		return bytes;
	}
}

async function readAsarIndex(source: ByteSource, options: FormatReadOptions): Promise<ArchiveIndexEntry[]> {

View on GitHub (pinned to 9690622007)

Solutions

  1. Restore the unpacked file to the exact content packed into the ASAR (re-extract from the original source)
  2. Regenerate the ASAR header (repack) if the unpacked file was intentionally updated
  3. Re-run your packaging tool so .asar and .unpacked are produced from the same build

Example fix

npx asar extract app.asar restore-dir/  # restore expected sidecar contents
# then repack:
npx asar pack app/ app.asar --unpack-dir assets
Defensive patterns

Strategy: validation

Validate before calling

const st = await Bun.file(sidecar).stat();
if (st.size !== entry.size) throw new Error(`sidecar size ${st.size} != header ${entry.size} for ${entry.path}`);

Try / catch

try { return await readMember(entry); } catch (e) { if (e instanceof ArchiveError && e.message.includes("size differs from its archive header")) { /* re-extract sidecar or repack archive */ } throw e; }

Prevention

When it happens

Trigger: Reading an unpacked member whose sidecar file was modified, truncated, or replaced since the ASAR was packed (stat.size !== header-declared size).

Common situations: Files updated in place in .unpacked after packaging; partial downloads or interrupted copies; repacking the .asar without regenerating the .unpacked sidecars; editors/IDEs rewriting files on save.

Related errors


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