{"record":{"id":"cec828983101d7a4","repo":"JuliusBrussee/caveman","slug":"pluginpath-already-exists-and-is-not-caveman-ow","errorCode":null,"errorMessage":"${pluginPath} already exists and is not Caveman-owned; refusing to overwrite it","messagePattern":"(.+?) already exists and is not Caveman-owned; refusing to overwrite it","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":7354,"sourceCode":"  for (const [providerID, route] of Object.entries(routes)) {\n    const provider = providers[providerID] && typeof providers[providerID] === \"object\" && !Array.isArray(providers[providerID]) ? providers[providerID] as Record<string, unknown> : {};\n    const options = provider.options && typeof provider.options === \"object\" && !Array.isArray(provider.options) ? provider.options as Record<string, unknown> : {};\n    previousRoutes[providerID] = options.baseURL ?? null;\n    options.baseURL = route;\n    provider.options = options;\n    providers[providerID] = provider;\n  }\n  root.provider = providers;\n  const mcp = root.mcp && typeof root.mcp === \"object\" && !Array.isArray(root.mcp) ? root.mcp as Record<string, unknown> : {};\n  const previousMcp = mcp.caveman;\n  const installedMcp = { type: \"local\", command: [mcpBinary], enabled: true };\n  mcp.caveman = installedMcp;\n  root.mcp = mcp;\n\n  const pluginPath = opencodeNativePluginPath();\n  const pluginBefore = fileBytes(pluginPath);\n  if (pluginBefore && !pluginBefore.toString(\"utf8\").includes(\"caveman:native-opencode\")) {\n    throw new Error(`${pluginPath} already exists and is not Caveman-owned; refusing to overwrite it`);\n  }\n  return [\n    {\n      file: configPath,\n      before,\n      after: Buffer.from(JSON.stringify(root, null, 2) + \"\\n\"),\n      kind: \"opencode-config\",\n      owned: { routes, previous_routes: previousRoutes, installed_mcp: installedMcp, previous_mcp: previousMcp ?? null },\n    },\n    {\n      file: pluginPath,\n      before: pluginBefore,\n      after: Buffer.from(opencodeNativePluginSource()),\n      kind: \"opencode-plugin\",\n    },\n  ];\n}\n","sourceCodeStart":7336,"sourceCodeEnd":7372,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/cli/src/index.ts#L7336-L7372","documentation":"During Caveman's native opencode install, the installer writes a generated plugin file at the path returned by opencodeNativePluginPath(). Before writing, it checks any existing file for the marker string 'caveman:native-opencode'; if the file exists but lacks that marker, it refuses to overwrite a file it does not own. This prevents silently clobbering a user's hand-written opencode plugin.","triggerScenarios":"Running the enable/install flow (`caveman` native opencode setup) when a file already exists at the plugin path and its contents do not contain the 'caveman:native-opencode' marker (e.g. a manually created plugin, or one from another tool).","commonSituations":"Users who already wrote a custom opencode plugin at the same location; leftover plugin files from a different tool or an older Caveman version whose marker changed; a partially edited Caveman plugin where the marker line was removed.","solutions":["Back up and delete or rename the existing plugin file, then re-run the install so Caveman can generate a fresh one.","If the file is yours, move it to a different path so the Caveman-owned path is free.","If you believe the file is a Caveman plugin missing its marker (e.g. edited), restore the 'caveman:native-opencode' marker line or reinstall the plugin via `caveman doctor`.","Re-run the enable command after clearing the path."],"exampleFix":"// before: existing non-Caveman plugin blocks install\n~/.config/opencode/plugins/native.ts  // user content, no marker\n// after: move or remove it, then re-run installer\nmv ~/.config/opencode/plugins/native.ts ~/native.ts.bak\n// installer now writes plugin containing: // caveman:native-opencode","handlingStrategy":"fallback","validationCode":"import { readFileSync, existsSync } from 'fs';\nconst p = opencodePluginPath();\nif (existsSync(p) && !readFileSync(p, 'utf8').includes('caveman:native-opencode')) {\n  // back up or move the file before running the installer\n}","typeGuard":null,"tryCatchPattern":"try {\n  await cavemanEnableOpencode();\n} catch (e) {\n  if (String(e.message).includes('already exists and is not Caveman-owned')) {\n    backupAndMove(pluginPath);\n    await cavemanEnableOpencode();\n  }\n}","preventionTips":["Do not hand-edit the Caveman-generated opencode plugin file.","Keep user plugins under different filenames than the Caveman-generated one.","After manual edits to generated files, re-run `caveman doctor` to verify ownership markers.","Back up config/plugin directories before running installers."],"tags":["install","config","refuse-overwrite","cli"],"backgroundTag":"file-already-exists","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"}