{"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":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":8254,"sourceCode":"      if (identity === `native-hook:${agent}`) return false;\n      return !expectedStrings.has(canonicalManagedHookEntry(entry));\n    });\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":8236,"sourceCodeEnd":8272,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/cli/src/index.ts#L8236-L8272","documentation":"While restoring an enable operation, the CLI compares the current bytes of the operation's target file with what existed before. If the file is now missing (`!current`) but the journal records that it existed before enable (`before_exists`), something deleted it after enable. Restoring would mean recreating a file whose prior content the backup may not fully capture, so the CLI refuses rather than perform a destructive operation.","triggerScenarios":"`restoreNativeOperation(operation)` where `fileBytes(operation.file)` returns null/empty while `operation.before_exists === true`.","commonSituations":"The user (or another tool) deleted the agent's settings/config file after running `caveman enable`; a reset script wiped the config directory; the file path moved between versions.","solutions":["Restore the deleted file from an external backup (git, editor history, OS backup) so the journal's before-state is meaningful, then retry disable.","If deletion is intentional, delete the journal operation entry for this file so disable skips it.","Recreate the file with the pre-enable content stored in the operation backup (`nativeBackupBytes`), then re-run disable.","Run `caveman doctor <agent> --fix` to rebuild the config from the journal, then disable."],"exampleFix":"// before: file missing, disable refuses\n$ caveman disable gemini\n// after: restore the file first, then disable\ncp ~/.config/gemini/settings.json.bak ~/.config/gemini/settings.json\ncaveman disable gemini","handlingStrategy":"validation","validationCode":"import { existsSync } from \"node:fs\";\nfor (const op of journal.operations) {\n  if (op.before_exists && !existsSync(op.file)) {\n    console.error(`refusing disable: ${op.file} was recorded pre-enable but is now missing`);\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Don't delete agent settings files while a caveman integration is enabled; disable first.","Back up config directories before running reset/cleanup scripts.","Keep agent config files under version control so accidental deletes are recoverable."],"tags":["file-deleted","journal","safety-guard","disable"],"backgroundTag":"file-not-found","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}