can1357/oh-my-pi · warning · ArchiveError
Unpacked ASAR file ' ' changed while being read
Error message
Unpacked ASAR file '${label}' changed while being read What it means
Thrown when the bytes actually read from the unpacked sidecar differ in length from the size obtained by stat() moments earlier. This indicates the file was modified concurrently during the read, so the returned buffer would be inconsistent with the header.
Solutions
- Stop processes that mutate the .unpacked tree while the app reads it; retry the read once the writer finishes
- Read from a stable installed copy rather than a live-build directory
- Use file locking or read a snapshot copy for assets that change
Example fix
// before await member.read(...) // while `vite build --watch` writes assets // after await buildComplete; // wait for writer, then read const bytes = await member.read(entry.size, entry.path);
Defensive patterns
Strategy: retry
Try / catch
for (let i = 0; i < 3; i++) {
try { return await readMember(entry); }
catch (e) { if (e instanceof ArchiveError && e.message.includes("changed while being read")) { await Bun.sleep(50); continue; } throw e; }
}
throw new Error(`file ${entry.path} is being modified concurrently`); Prevention
- Stop watch/build processes writing .unpacked during runtime reads
- Run a single app instance against one install directory
- Snapshot assets before reading if updaters may rewrite them
When it happens
Trigger: Another process wrote/truncated/replaced the .unpacked file between stat() and file.bytes(); a build watch process regenerated the file while the app was reading it.
Common situations: Dev hot-reload tooling touching unpacked assets at runtime; two app instances sharing one install directory; package managers or updaters swapping files while the app runs.
Related errors
- Agent " " was replaced during session initialization.
- Archive file ' ' is unpacked and requires a…
- Daemon is already starting
- Failed to acquire lock for
- Failed to read unpacked ASAR file
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/35a7d50616715124.
Report an issue: GitHub.
Appendix: source
Thrown at packages/utils/src/ar/asar.ts:174
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");
}
if (readUInt32LE(sizePickle, 0) !== 4) {
throw invalidAsar("invalid size pickle");
}View on GitHub (pinned to 9690622007)