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
- Inspect the wrapped cause in the message (describeError output) to find the real underlying failure (IO, range, permissions).
- Re-verify the ASAR file is complete and readable (size, permissions) before parsing; re-download if truncated.
- Check that offsets/sizes in the header are within the file's bounds — out-of-range reads indicate a corrupt or malicious header.
- 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
- Ensure the ASAR file is fully written and closed before parsing (no concurrent writers).
- Check file permissions and filesystem health when reading from mounts/network drives.
- If you implement custom ByteSource, throw ArchiveError for domain failures so member context is preserved.
- Validate header offsets/sizes against the file length before reading to catch corrupt headers early.
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
- ASAR member '${formatArchivePathForError(memberPath)}' is tr
- ${error instanceof Error ? error.message : String(error)}
- Unable to read ARJ archive: ${error instanceof Error ? error
- Invalid ARJ archive: truncated data
- ASAR member '${formatArchivePathForError(memberPath)}' faile
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/1621c604623362e4.
Report an issue: GitHub.