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

  1. Identify the file named in the error and diff it against the agent's expected config and your recent edits.
  2. 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.
  3. 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

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


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/ba03cba624f6f57a. Report an issue: GitHub.