paperclipai/paperclip · error · Error
ACPX executable changed during snapshot
Error message
ACPX executable changed during snapshot
What it means
After reading the executable's bytes, createAcpxPrivateSnapshot re-stats the source file and compares it to the stat taken before reading. If size/mtime/inode changed between the two stats, the executable was concurrently modified and the snapshot would be a torn, inconsistent copy, so it throws instead of writing a corrupt snapshot.
Source
Thrown at packages/paperclip-runner/src/drivers/acpx/private-snapshot.ts:199
if (error.code !== "EEXIST") throw error;
},
);
}
let executablePath: string | null = null;
if (executable) {
const before = await executable.stat({ bigint: true });
if (!before.isFile() || before.size < 1n || before.size > BigInt(MAX_ACPX_RUNTIME_EXECUTABLE_BYTES)) {
throw new Error("ACPX runtime executable must be a bounded executable file");
}
// The bigint bound above makes this conversion exact before allocation.
const executableBytes = Number(before.size);
bytesCopied += executableBytes;
if (bytesCopied > MAX_SNAPSHOT_BYTES) {
throw new Error("ACPX snapshot exceeds its byte bound");
}
const bytes = await readSnapshotBytes(executable, executableBytes);
if (!same(before, await executable.stat({ bigint: true })))
throw new Error("ACPX executable changed during snapshot");
executablePath = join(directory, "runtime");
await writeFile(executablePath, bytes, { flag: "wx", mode: 0o500 });
digests[executablePath] = digest(bytes);
}
const manifest = Buffer.from(
JSON.stringify({ roots, executable: executablePath, digests }),
);
const manifestPath = join(directory, "manifest.json");
await writeFile(manifestPath, manifest, { flag: "wx", mode: 0o400 });
for (const dir of new Set(directories)) await chmod(dir, 0o500);
return {
roots,
executable: executablePath,
digests,
handoff: { path: manifestPath, digest: digest(manifest) },
close,
};
} catch (error) {View on GitHub (pinned to 01ad858492)
Solutions
- Re-run the snapshot once the concurrent process (package manager, updater, build) has finished; the check is TOCTOU protection and usually succeeds on retry.
- Identify what mutates the executable (lsof/fuser on the path) and stop it from running concurrently.
- Pin/lock the ACPX runtime version so installs do not replace the binary mid-session.
- Exclude the runtime directory from antivirus/indexer interference, or move the executable to a stable location referenced by config.
Example fix
// before
await driver.snapshot(); // raced with `pnpm install` replacing the binary
// after
await exec("pnpm install --frozen-lockfile"); // quiesce first
await driver.snapshot(); Defensive patterns
Strategy: retry
Try / catch
try {
await driver.snapshot();
} catch (e) {
if (e.message === "ACPX executable changed during snapshot") {
await waitForQuiescence(); // ensure no install/update is running
return retrySnapshot(3);
}
throw e;
} Prevention
- Do not run pnpm install, updaters, or builds concurrently with ACPX sessions.
- Pin the runtime binary version with a lockfile.
- Exclude the runtime path from antivirus/backup tools that rewrite files.
When it happens
Trigger: Calling snapshot()/privateSnapshot() while another process (package manager, updater, build script, antivirus quarantine/rewrite) replaces or rewrites the ACPX runtime executable between the initial stat and the post-read verification stat.
Common situations: Running pnpm/yarn install or a build that relinks binaries in the same session; an auto-updater running concurrently; copying the repo while a tool rewrites timestamps; docker/CI image layers being mutated mid-run.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- ACPX ${agent} runtime executable changed while it was verifi
- ACPX provider ownership admission is already active
- ACPX ${agent} runtime executable must be a real regular file
- ACPX ${agent} runtime executable could not be opened as a no
- ACPX ${agent} runtime executable must be a bounded executabl
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/2a3627abd28d989f.
Report an issue: GitHub.