can1357/oh-my-pi · error · ArchiveError

Failed to read ASAR member '${formatArchivePathForError(memb

Error message

Failed to read ASAR member '${formatArchivePathForError(memberPath)}': ${describeError(error)}

What it means

When the underlying byte-source read for an ASAR member throws a non-ArchiveError (I/O failure, permission error, out-of-range slice, etc.), the reader wraps it in an ArchiveError that names the member and the original cause via describeError, so callers get one consistent error type with member context instead of a raw low-level exception.

Source

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

	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;
	}

	async read(size: number, memberPath: string): Promise<Uint8Array> {
		if (size !== this.#size) {
			throw new ArchiveError(`ASAR member '${formatArchivePathForError(memberPath)}' has an inconsistent size`);
		}
		let bytes: Uint8Array;
		try {
			bytes = await this.#source.read(this.#offset, this.#offset + this.#size);
		} catch (error) {
			if (error instanceof ArchiveError) throw error;
			throw new ArchiveError(
				`Failed to read ASAR member '${formatArchivePathForError(memberPath)}': ${describeError(error)}`,
			);
		}
		if (bytes.byteLength !== this.#size) {
			throw new ArchiveError(`ASAR member '${formatArchivePathForError(memberPath)}' is truncated`);
		}
		verifyIntegrity(bytes, this.#integrity, memberPath);
		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;

View on GitHub (pinned to 9690622007)

Solutions

  1. Inspect the wrapped cause in the message (describeError output) to find the real underlying failure (IO, range, permissions).
  2. Re-verify the ASAR file is complete and readable (size, permissions) before parsing; re-download if truncated.
  3. Check that offsets/sizes in the header are within the file's bounds — out-of-range reads indicate a corrupt or malicious header.
  4. If you supply a custom ByteSource, make sure its read(end) throws ArchiveError for domain failures or handles bounds correctly.

Example fix

// before
const bytes = await readAsarMember(file, path); // raw IO error surfaces wrapped
// after
try {
  const bytes = await readAsarMember(file, path);
} catch (e) {
  if (e instanceof ArchiveError && e.message.includes("Failed to read ASAR member")) {
    logger.error("ASAR member unreadable", { cause: e.message });
    await reAcquireAsar();
  }
  throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Confirm the backing file is readable and large enough before member reads.
const stat = await fs.stat(asarPath);
await fs.access(asarPath, fs.constants.R_OK);
if (stat.size < headerExpectedTotal) throw new Error("ASAR smaller than its header claims");

Type guard

function isArchiveError(e: unknown): e is ArchiveError {
	return e instanceof ArchiveError;
}

Try / catch

try {
	const bytes = await member.read(size, path);
} catch (e) {
	if (!isArchiveError(e)) throw e; // already-wrapped errors keep member context in e.message
	if (e.message.includes("Failed to read ASAR member")) {
		// parse the wrapped cause (describeError output) and act on the real IO failure
		logger.error("ASAR member read failed", { member: path, cause: e.message });
	}
	throw e;
}

Prevention

When it happens

Trigger: PackedAsarMemberSource.read → this.#source.read(offset, offset+size) rejects with anything that is not already an ArchiveError — e.g. the backing buffer/file read fails, an out-of-bounds range, or a permission/IO error from the source implementation.

Common situations: File deleted or truncated between header parse and member read; reading an ASAR on a flaky mount/network drive; custom ByteSource implementations throwing on out-of-range offsets for a corrupt header; permissions issues.

Related errors


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