JuliusBrussee/caveman · error
already exists and is not Caveman-owned; refusing to…
Error message
${pluginPath} already exists and is not Caveman-owned; refusing to overwrite it What it means
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.
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.
Example fix
// before: existing non-Caveman plugin blocks install ~/.config/opencode/plugins/native.ts // user content, no marker // after: move or remove it, then re-run installer mv ~/.config/opencode/plugins/native.ts ~/native.ts.bak // installer now writes plugin containing: // caveman:native-opencode
Defensive patterns
Strategy: fallback
Validate before calling
import { readFileSync, existsSync } from 'fs';
const p = opencodePluginPath();
if (existsSync(p) && !readFileSync(p, 'utf8').includes('caveman:native-opencode')) {
// back up or move the file before running the installer
} Try / catch
try {
await cavemanEnableOpencode();
} catch (e) {
if (String(e.message).includes('already exists and is not Caveman-owned')) {
backupAndMove(pluginPath);
await cavemanEnableOpencode();
}
} Prevention
- 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.
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- already exists and is not Caveman-owned; refusing to…
- : MCP ownership journal failed; native config may already…
- cave_live_eval_sandbox_profile_invalid
- caveman build: invalid .caveman/provider.json
- exists and is not exact Caveman-owned content; refusing to…
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/cec828983101d7a4.
Report an issue: GitHub.
Appendix: source
Thrown at packages/cli/src/index.ts:7354
for (const [providerID, route] of Object.entries(routes)) {
const provider = providers[providerID] && typeof providers[providerID] === "object" && !Array.isArray(providers[providerID]) ? providers[providerID] as Record<string, unknown> : {};
const options = provider.options && typeof provider.options === "object" && !Array.isArray(provider.options) ? provider.options as Record<string, unknown> : {};
previousRoutes[providerID] = options.baseURL ?? null;
options.baseURL = route;
provider.options = options;
providers[providerID] = provider;
}
root.provider = providers;
const mcp = root.mcp && typeof root.mcp === "object" && !Array.isArray(root.mcp) ? root.mcp as Record<string, unknown> : {};
const previousMcp = mcp.caveman;
const installedMcp = { type: "local", command: [mcpBinary], enabled: true };
mcp.caveman = installedMcp;
root.mcp = mcp;
const pluginPath = opencodeNativePluginPath();
const pluginBefore = fileBytes(pluginPath);
if (pluginBefore && !pluginBefore.toString("utf8").includes("caveman:native-opencode")) {
throw new Error(`${pluginPath} already exists and is not Caveman-owned; refusing to overwrite it`);
}
return [
{
file: configPath,
before,
after: Buffer.from(JSON.stringify(root, null, 2) + "\n"),
kind: "opencode-config",
owned: { routes, previous_routes: previousRoutes, installed_mcp: installedMcp, previous_mcp: previousMcp ?? null },
},
{
file: pluginPath,
before: pluginBefore,
after: Buffer.from(opencodeNativePluginSource()),
kind: "opencode-plugin",
},
];
}
View on GitHub (pinned to 3ee70a1026)