can1357/oh-my-pi · error · ArchiveError

ASAR member '${label}' has an inconsistent size

Error message

ASAR member '${label}' has an inconsistent size

What it means

This ArchiveError is thrown by UnpackedAsarMemberSource.read when the `size` argument passed by the archive framework does not match the member size recorded in the ASAR header. It is an internal consistency check: the caller must request exactly the byte count the index declares for this file. A mismatch means either the caller passed a wrong size or the archive index was built from inconsistent metadata.

Source

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

		return bytes;
	}
}

class UnpackedAsarMemberSource implements MemberSource {
	readonly #filePath?: string;
	readonly #size: number;
	readonly #integrity?: AsarIntegrity;

	constructor(filePath: string | undefined, size: number, integrity: AsarIntegrity | undefined) {
		this.#filePath = filePath;
		this.#size = size;
		this.#integrity = integrity;
	}

	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 {

View on GitHub (pinned to 9690622007)

Solutions

  1. Ensure the size passed to read() comes from the same ArchiveIndexEntry the MemberSource was created from (entry.size), not a separately computed value
  2. Re-read the archive index so entry metadata and member sources are in sync
  3. Check whether custom code caches entry sizes across re-parses and clear that cache

Example fix

// before
const bytes = await member.read(myEstimatedSize, entry.path);
// after
const bytes = await member.read(entry.size, entry.path);
Defensive patterns

Strategy: validation

Validate before calling

if (requestedSize !== entry.size) throw new Error(`size mismatch for ${entry.path}: ${requestedSize} != ${entry.size}`);
await member.read(entry.size, entry.path);

Type guard

function isEntrySize(entry, size) { return size === entry.size; }

Try / catch

try { bytes = await member.read(entry.size, entry.path); } catch (e) { if (e instanceof ArchiveError && e.message.includes("inconsistent size")) { /* re-read fresh index and retry */ } else throw e; }

Prevention

When it happens

Trigger: Calling read() on an unpacked ASAR member entry with a size argument different from the entry's declared size in the ASAR JSON header (e.g. reading with a stale size after the index was re-parsed, or a framework caller computing size from the wrong entry).

Common situations: Bugs in code that resolves archive entries by path and passes the wrong entry's size; custom tooling that manually reads members instead of going through the archive API; corrupted or hand-edited ASAR headers.

Related errors


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