can1357/oh-my-pi · error · ArchiveError

Unpacked ASAR file ' ' size differs from its archive header…

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.

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.

Appendix: 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)