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

  1. Check file permissions on the .unpacked tree (readable by the process user) and fix with chmod/chown
  2. Inspect the embedded cause message for the exact errno and address it (disk, lock, permission)
  3. 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

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


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