JuliusBrussee/caveman · error · Error

${operation.file} was removed after enable; refusing destruc

Error message

${operation.file} was removed after enable; refusing destructive disable

What it means

restoreNativeOperation() refuses when a journaled file (before_exists true - it existed before enable) is now missing from disk. Caveman's own writes only replace files, never delete them, so a vanished file means something outside the transaction removed it; disable halts rather than guess whether recreating it is wanted.

Source

Thrown at packages/cli/src/index.ts:7559

      }
    }
    const kept = list.filter((entry) => !expectedStrings.has(JSON.stringify(entry)));
    if (kept.length > 0) hooks[event] = kept;
    else delete hooks[event];
  }
  if (Object.keys(hooks).length === 0) delete root.hooks;
  return root;
}

function jsonBytes(root: Record<string, unknown>): Buffer {
  return Buffer.from(JSON.stringify(root, null, 2) + "\n");
}

function restoreNativeOperation(operation: NativeJournal["operations"][number]): Buffer | null {
  const current = fileBytes(operation.file);
  const before = nativeBackupBytes(operation);
  if (!current) {
    if (operation.before_exists) throw new Error(`${operation.file} was removed after enable; refusing destructive disable`);
    return null;
  }
  if (bytesHash(current) === operation.after_sha256) return before;

  if (operation.kind === "claude-settings") {
    const currentRoot = parseJsonFileObject(operation.file, current);
    const beforeRoot = parseJsonFileObject(operation.file, before);
    const currentEnv = currentRoot.env && typeof currentRoot.env === "object" && !Array.isArray(currentRoot.env)
      ? currentRoot.env as Record<string, unknown>
      : {};
    const beforeEnv = beforeRoot.env && typeof beforeRoot.env === "object" && !Array.isArray(beforeRoot.env)
      ? beforeRoot.env as Record<string, unknown>
      : {};
    const route = operation.owned?.route;
    if (currentEnv.ANTHROPIC_BASE_URL !== undefined && currentEnv.ANTHROPIC_BASE_URL !== route) {
      throw new Error("Claude ANTHROPIC_BASE_URL changed after enable; refusing destructive disable");
    }
    if (currentEnv.ANTHROPIC_BASE_URL === route) {

View on GitHub (pinned to 2f49f0e1a3)

Solutions

  1. Recreate the file, then re-run disable. The simplest source is the journal backup: the error names the file path, and the matching bytes are in ~/.caveman/integrations/backups/<agent>/<uuid>/<i>.bin.
  2. Or restore the file from your own dotfile backup.
  3. Run `caveman doctor <agent>` first - its checks table shows present:false for the missing file and names the journal entries involved.

Example fix

// before
$ caveman disable claude
Error: ~/.claude/settings.json was removed after enable; refusing destructive disable

// after
$ cp ~/.caveman/integrations/backups/claude/<uuid>/0.bin ~/.claude/settings.json
$ caveman disable claude
Defensive patterns

Strategy: validation

Validate before calling

import { readFileSync } from 'node:fs';
const journal = JSON.parse(readFileSync(`${process.env.HOME}/.caveman/integrations/claude.json`, 'utf8'));
for (const op of journal.operations) {
  if (op.before_exists) {
    try { readFileSync(op.file); } catch { console.error(`${op.file} is missing; recreate it before 'caveman disable claude'`); process.exit(1); }
  }
}

Prevention

When it happens

Trigger: `caveman disable <agent>` after the journaled config file (e.g. ~/.claude/settings.json or the codex config.toml named in the journal) was deleted, moved, or renamed by the user, a cleaner, or another tool.

Common situations: Switching configs by renaming (settings.json.dev); the agent resetting its own config on startup; cleanup scripts or dotfile managers removing 'unknown' files.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@2f49f0e1a3 (2026-08-18). Data as JSON: /api/errors/b8d4c363b3bd2d2f. Report an issue: GitHub.