{"record":{"id":"1621c604623362e4","repo":"can1357/oh-my-pi","slug":"failed-to-read-asar-member-formatarchivepathfor","errorCode":null,"errorMessage":"Failed to read ASAR member '${formatArchivePathForError(memberPath)}': ${describeError(error)}","messagePattern":"Failed to read ASAR member '(.+?)': (.+?)","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/asar.ts","lineNumber":124,"sourceCode":"\treadonly #integrity?: AsarIntegrity;\n\n\tconstructor(source: ByteSource, offset: number, size: number, integrity: AsarIntegrity | undefined) {\n\t\tthis.#source = source;\n\t\tthis.#offset = offset;\n\t\tthis.#size = size;\n\t\tthis.#integrity = integrity;\n\t}\n\n\tasync read(size: number, memberPath: string): Promise<Uint8Array> {\n\t\tif (size !== this.#size) {\n\t\t\tthrow new ArchiveError(`ASAR member '${formatArchivePathForError(memberPath)}' has an inconsistent size`);\n\t\t}\n\t\tlet bytes: Uint8Array;\n\t\ttry {\n\t\t\tbytes = await this.#source.read(this.#offset, this.#offset + this.#size);\n\t\t} catch (error) {\n\t\t\tif (error instanceof ArchiveError) throw error;\n\t\t\tthrow new ArchiveError(\n\t\t\t\t`Failed to read ASAR member '${formatArchivePathForError(memberPath)}': ${describeError(error)}`,\n\t\t\t);\n\t\t}\n\t\tif (bytes.byteLength !== this.#size) {\n\t\t\tthrow new ArchiveError(`ASAR member '${formatArchivePathForError(memberPath)}' is truncated`);\n\t\t}\n\t\tverifyIntegrity(bytes, this.#integrity, memberPath);\n\t\treturn bytes;\n\t}\n}\n\nclass UnpackedAsarMemberSource implements MemberSource {\n\treadonly #filePath?: string;\n\treadonly #size: number;\n\treadonly #integrity?: AsarIntegrity;\n\n\tconstructor(filePath: string | undefined, size: number, integrity: AsarIntegrity | undefined) {\n\t\tthis.#filePath = filePath;","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/asar.ts#L106-L142","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst bytes = await readAsarMember(file, path); // raw IO error surfaces wrapped\n// after\ntry {\n  const bytes = await readAsarMember(file, path);\n} catch (e) {\n  if (e instanceof ArchiveError && e.message.includes(\"Failed to read ASAR member\")) {\n    logger.error(\"ASAR member unreadable\", { cause: e.message });\n    await reAcquireAsar();\n  }\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"// Confirm the backing file is readable and large enough before member reads.\nconst stat = await fs.stat(asarPath);\nawait fs.access(asarPath, fs.constants.R_OK);\nif (stat.size < headerExpectedTotal) throw new Error(\"ASAR smaller than its header claims\");","typeGuard":"function isArchiveError(e: unknown): e is ArchiveError {\n\treturn e instanceof ArchiveError;\n}","tryCatchPattern":"try {\n\tconst bytes = await member.read(size, path);\n} catch (e) {\n\tif (!isArchiveError(e)) throw e; // already-wrapped errors keep member context in e.message\n\tif (e.message.includes(\"Failed to read ASAR member\")) {\n\t\t// parse the wrapped cause (describeError output) and act on the real IO failure\n\t\tlogger.error(\"ASAR member read failed\", { member: path, cause: e.message });\n\t}\n\tthrow e;\n}","preventionTips":["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."],"tags":["archive","asar","io","error-wrapping"],"backgroundTag":"read-failure","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}