{"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":6352,"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":6334,"sourceCodeEnd":6370,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/cli/src/index.ts#L6334-L6370","documentation":"opencodeNativeMutations() writes a Caveman-owned plugin file (opencodeNativePluginPath(), an opencode plugin JS file) and only overwrites it when the existing content contains the \"caveman:native-opencode\" ownership marker. Any pre-existing file without that marker is treated as user-owned and protected from overwrite.","triggerScenarios":"Native opencode install when the plugin file path already exists and its contents lack the caveman:native-opencode marker string.","commonSituations":"User (or another tool) already placed their own plugin at that path; a leftover plugin from an incompatible/older caveman version whose marker text changed; manually created stub file.","solutions":["Open the plugin file, confirm it is not something you need, and move it aside (e.g. plugin.js.bak) or delete it","If it came from an old caveman install, delete it so the current version rewrites it with the current marker","Re-run the opencode native install; it will now create the file with proper ownership marker"],"exampleFix":"# before\n$ ls ~/.config/opencode/plugin/caveman.js   # exists, user-authored\nError: .../caveman.js already exists and is not Caveman-owned; refusing to overwrite it\n\n# after\n$ mv ~/.config/opencode/plugin/caveman.js ~/caveman.js.bak\n$ caveman native install opencode   # recreates Caveman-owned plugin","handlingStrategy":"validation","validationCode":"import { existsSync, readFileSync } from \"node:fs\";\nfunction pluginFileSafeToOwn(path: string): boolean {\n  if (!existsSync(path)) return true;\n  try { return readFileSync(path, \"utf8\").includes(\"caveman:native-opencode\"); }\n  catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"try { nativeInstallOpencode(); } catch (e) {\n  if (e instanceof Error && /not Caveman-owned/.test(e.message)) {\n    backUpAndRemovePlugin(); nativeInstallOpencode();\n  } else throw e;\n}","preventionTips":["Don't hand-author files at paths installers reserve; check the tool's plugin path first","When reusing dotfile repos, exclude tool-generated plugin files","Never edit Caveman-owned plugin files; regenerate via the installer"],"tags":["opencode","plugin","ownership","refuse-overwrite","filesystem"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}