{"record":{"id":"b8d4c363b3bd2d2f","repo":"JuliusBrussee/caveman","slug":"operation-file-was-removed-after-enable-refusi","errorCode":null,"errorMessage":"${operation.file} was removed after enable; refusing destructive disable","messagePattern":"(.+?) was removed after enable; refusing destructive disable","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":7559,"sourceCode":"      }\n    }\n    const kept = list.filter((entry) => !expectedStrings.has(JSON.stringify(entry)));\n    if (kept.length > 0) hooks[event] = kept;\n    else delete hooks[event];\n  }\n  if (Object.keys(hooks).length === 0) delete root.hooks;\n  return root;\n}\n\nfunction jsonBytes(root: Record<string, unknown>): Buffer {\n  return Buffer.from(JSON.stringify(root, null, 2) + \"\\n\");\n}\n\nfunction restoreNativeOperation(operation: NativeJournal[\"operations\"][number]): Buffer | null {\n  const current = fileBytes(operation.file);\n  const before = nativeBackupBytes(operation);\n  if (!current) {\n    if (operation.before_exists) throw new Error(`${operation.file} was removed after enable; refusing destructive disable`);\n    return null;\n  }\n  if (bytesHash(current) === operation.after_sha256) return before;\n\n  if (operation.kind === \"claude-settings\") {\n    const currentRoot = parseJsonFileObject(operation.file, current);\n    const beforeRoot = parseJsonFileObject(operation.file, before);\n    const currentEnv = currentRoot.env && typeof currentRoot.env === \"object\" && !Array.isArray(currentRoot.env)\n      ? currentRoot.env as Record<string, unknown>\n      : {};\n    const beforeEnv = beforeRoot.env && typeof beforeRoot.env === \"object\" && !Array.isArray(beforeRoot.env)\n      ? beforeRoot.env as Record<string, unknown>\n      : {};\n    const route = operation.owned?.route;\n    if (currentEnv.ANTHROPIC_BASE_URL !== undefined && currentEnv.ANTHROPIC_BASE_URL !== route) {\n      throw new Error(\"Claude ANTHROPIC_BASE_URL changed after enable; refusing destructive disable\");\n    }\n    if (currentEnv.ANTHROPIC_BASE_URL === route) {","sourceCodeStart":7541,"sourceCodeEnd":7577,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/2f49f0e1a352aa810e70056b7930aeb0b3d219b4/packages/cli/src/index.ts#L7541-L7577","documentation":"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.","triggerScenarios":"`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.","commonSituations":"Switching configs by renaming (settings.json.dev); the agent resetting its own config on startup; cleanup scripts or dotfile managers removing 'unknown' files.","solutions":["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.","Or restore the file from your own dotfile backup.","Run `caveman doctor <agent>` first - its checks table shows present:false for the missing file and names the journal entries involved."],"exampleFix":"// before\n$ caveman disable claude\nError: ~/.claude/settings.json was removed after enable; refusing destructive disable\n\n// after\n$ cp ~/.caveman/integrations/backups/claude/<uuid>/0.bin ~/.claude/settings.json\n$ caveman disable claude","handlingStrategy":"validation","validationCode":"import { readFileSync } from 'node:fs';\nconst journal = JSON.parse(readFileSync(`${process.env.HOME}/.caveman/integrations/claude.json`, 'utf8'));\nfor (const op of journal.operations) {\n  if (op.before_exists) {\n    try { readFileSync(op.file); } catch { console.error(`${op.file} is missing; recreate it before 'caveman disable claude'`); process.exit(1); }\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Do not delete or rename journaled agent config files while an integration is enabled","Keep dotfile backups of every file caveman enable reports writing","Run `caveman doctor <agent>` after agents reset their own configs"],"tags":["disable","missing-file","config-drift","restore"],"backgroundTag":"config-drift-refusal","analyzedSha":"2f49f0e1a352aa810e70056b7930aeb0b3d219b4","analyzedAt":"2026-08-18T03:14:35.516Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}