JuliusBrussee/caveman · error
${operation.file} changed during interrupted ${agent} instal
Error message
${operation.file} changed during interrupted ${agent} install; refusing recovery What it means
During recovery of an interrupted native install, each journaled file must hash-match either its recorded post-install content (after_sha256) or its pre-install content (before_sha256 / before_exists=false meaning absent). If a file matches neither, something modified it between the crash and recovery, and restoring backups would clobber unknown changes — so recovery refuses. The same guard protects the rollback path.
Source
Thrown at packages/cli/src/index.ts:6913
if (!pending) return false;
const committed = readNativeJournal(agent);
if (committed) {
if (JSON.stringify(committed) !== JSON.stringify(pending)) {
throw new Error(`conflicting committed and pending integration journals for ${agent}; refusing recovery`);
}
unlinkSync(nativePendingJournalPath(agent));
return false;
}
const current = pending.operations.map((operation) => ({ file: operation.file, bytes: fileBytes(operation.file) }));
const restored = pending.operations.map((operation) => {
const before = nativeBackupBytes(operation);
const now = fileBytes(operation.file);
const isInstalled = Boolean(now && bytesHash(now) === operation.after_sha256);
const isBefore = operation.before_exists
? Boolean(now && operation.before_sha256 && bytesHash(now) === operation.before_sha256)
: now === null;
if (!isInstalled && !isBefore) {
throw new Error(`${operation.file} changed during interrupted ${agent} install; refusing recovery`);
}
return { file: operation.file, bytes: before };
});
try {
for (const item of restored) writeNativeRestoration(item.file, item.bytes);
unlinkSync(nativePendingJournalPath(agent));
} catch (error) {
for (const item of current) {
try { writeNativeRestoration(item.file, item.bytes); } catch { /* original error remains authority */ }
}
throw error;
}
process.stderr.write(`${mark("warn")} recovered interrupted ${agent} integration change before continuing\n`);
return true;
}
function nativeMutationsFor(agent: NativeAgent, gw: string, mcpBinary: string | undefined): NativeMutation[] {
return agent === "claude"View on GitHub (pinned to 27d5a3981a)
Solutions
- Identify the file named in the error and diff it against the agent's expected config and your recent edits.
- Back up the changed file, then either re-run the interrupted install (which overwrites toward after_sha256) or restore the pre-install content manually and re-run.
- Remove the pending journal only after you have reconciled the file, so recovery stops tripping on it.
Example fix
# before: user edits settings between crash and recovery caveman recover # refuses: settings.json changed during interrupted install # after: reconcile then re-run cp settings.json settings.json.bak && caveman install claude
Defensive patterns
Strategy: validation
Validate before calling
import { createHash } from "node:crypto";
import { readFileSync } from "node:fs";
function fileMatchesJournal(file: string, before?: string, after?: string): boolean {
let bytes: Buffer;
try { bytes = readFileSync(file); } catch { return before === undefined; }
const sha = createHash("sha256").update(bytes).digest("hex");
return sha === after || sha === before;
} Try / catch
try {
runRecovery(agent);
} catch (e) {
if (e instanceof Error && e.message.includes("changed during interrupted")) {
const file = e.message.split(" ")[0]; // first token is the file path
backupAndReconcile(file); // operator decision, then re-run install
return runInstall(agent);
}
throw e;
} Prevention
- Do not edit agent settings files between a crashed install and recovery.
- Stop the agent process before running install/recovery so it cannot rewrite its config concurrently.
- Keep the pending journal until state is verified consistent; deleting it loses recovery info.
When it happens
Trigger: Recovery runs after an interrupted install and a target file (e.g. an agent settings file) was edited by the user or by the agent itself since the crash; fileBytes(file) hashed against both before_sha256 and after_sha256 fails both checks.
Common situations: User opens and saves their Claude/Codex settings file after a crashed install, an agent rewrites its own config at startup, editors that touch mtime/content (formatters, sync tools), or a partially-restored backup from a prior recovery attempt.
Related errors
- conflicting committed and pending integration journals for $
- cave_harness_request_invalid
- cave_eve_terminal_${result.status}
- unknown command ${JSON.stringify(command)}; run caveman-agen
- usage: caveman-agent doctor [--json]
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/ba03cba624f6f57a.
Report an issue: GitHub.