can1357/oh-my-pi · error · ArchiveError
Failed to read unpacked ASAR file '${label}': ${describeErro
Error message
Failed to read unpacked ASAR file '${label}': ${describeError(error)} What it means
Wraps an unexpected I/O error from reading the unpacked sidecar file's bytes (after stat succeeded). The original error message is embedded via describeError so the underlying cause (permissions, EBUSY, etc.) is preserved in an ArchiveError.
Source
Thrown at packages/utils/src/ar/asar.ts:171
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[]> {
if (!Number.isSafeInteger(source.size) || source.size < ASAR_JSON_OFFSET) {
throw invalidAsar("truncated header");
}
const sizePickle = await source.read(0, ASAR_PICKLE_PREFIX_SIZE);
if (sizePickle.byteLength !== ASAR_PICKLE_PREFIX_SIZE) {
throw invalidAsar("truncated size pickle");
}View on GitHub (pinned to 9690622007)
Solutions
- Check file permissions on the .unpacked tree (readable by the process user) and fix with chmod/chown
- Inspect the embedded cause message for the exact errno and address it (disk, lock, permission)
- Retest with security software / filesystem overlays disabled to rule out interference
Example fix
// before chmod 600 app.asar.unpacked/assets/* // after chmod -R u+r app.asar.unpacked/
Defensive patterns
Strategy: try-catch
Validate before calling
try { await fs.access(sidecar, fs.constants.R_OK); } catch { throw new Error(`no read permission on ${sidecar}`); } Try / catch
try { return await readMember(entry); } catch (e) { if (e instanceof ArchiveError && e.message.startsWith("Failed to read unpacked ASAR file")) { logger.error("sidecar read failed", { cause: e.message }); } throw e; } Prevention
- Ensure the process user can read the entire .unpacked tree
- Exclude .unpacked from overzealous antivirus/backup locks
- Handle embedded errno from the wrapped cause message
When it happens
Trigger: Bun.file(path).bytes() rejecting with a non-ENOENT error: EACCES/EPERM on the file, EIO, file locked by another process, or a race where the file is deleted between stat and read.
Common situations: Running the app as a user without read permission on .unpacked contents; antivirus/indexers holding the file; NFS/network volumes dropping the file mid-read; SELinux or sandbox restrictions.
Related errors
- {}: {error}
- inter-device move failed: {} to {}; unable to remove target:
- Permission denied
- cannot stat {file}: {error}
- failed to read filter definition {}: {e}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/54ac1a070a8c2173.
Report an issue: GitHub.