JuliusBrussee/caveman · error
Claude caveman-cloud MCP changed after setup; refusing to ov
Error message
Claude caveman-cloud MCP changed after setup; refusing to overwrite user fields
What it means
Claude-specific preflight with a marker present: the live ~/.claude.json caveman-cloud registration (command, args, shape) does not match what the marker records. That means someone edited the registration after Caveman installed it — envs, command path, or extra args changed — and setup refuses to overwrite those user fields.
Source
Thrown at packages/cli/src/index.ts:2560
if (!existingBundle) {
if (current && !current.equals(Buffer.from(body))) {
throw new Error(`${file} already exists with non-canonical content; refusing to overwrite an unjournaled skill`);
}
continue;
}
const previous = previousSkills.get(file);
if (current && !current.equals(Buffer.from(body)) && (!previous || bytesHash(current) !== previous.after_sha256)) {
throw new Error(`${file} changed after setup; refusing to overwrite user skill edits`);
}
}
if (agent === "claude") {
const actual = claudeMcpRegistration("caveman-cloud");
const marker = readMcpServerMarker("claude", "caveman-cloud");
if (actual.present && !marker) {
throw new Error("Claude caveman-cloud MCP exists but is not Caveman-journaled; refusing overwrite");
}
if (actual.present && marker && !agentNativeCloudMcpMatches("claude", marker)) {
throw new Error("Claude caveman-cloud MCP changed after setup; refusing to overwrite user fields");
}
return;
}
const config = fileBytes(join(homedir(), ".codex", "config.toml"))?.toString("utf8") ?? "";
if (!config.includes("[mcp_servers.caveman-cloud]")) return;
if (!readMcpServerMarker("codex", "caveman-cloud")) {
throw new Error("[mcp_servers.caveman-cloud] exists but is not Caveman-journaled; refusing overwrite");
}
}
function installAgentNativeBundleSkills(agent: "claude" | "codex", journal: AgentNativeBundleJournal): void {
const originals = new Map(journal.skills.map((skill) => [skill.file, skill.before_base64]));
journal.skills = agentNativeSkillFiles(agent).map(({ file, body }) => {
mkdirSync(dirname(file), { recursive: true });
atomicWriteFile(file, Buffer.from(body));
return {
file,
before_base64: originals.get(file) ?? null,View on GitHub (pinned to 27d5a3981a)
Solutions
- Revert your manual edits to the caveman-cloud entry (restore the marker's recorded command/args) so setup can proceed
- Or delete both the entry and the marker, then re-run setup for a clean, consistent install
- If you need a custom command, keep it under a different server name than caveman-cloud
Defensive patterns
Strategy: validation
Validate before calling
function claudeMcpMatchesMarker(): boolean {
const cfg = JSON.parse(readFileSync(join(homedir(), ".claude.json"), "utf8"));
const live = cfg.mcpServers?.["caveman-cloud"];
if (!live) return true;
let marker: { command: string; args: string[] } | null = null;
try { marker = JSON.parse(readFileSync(markerPath, "utf8")); } catch { /* absent handled elsewhere */ }
return !marker || (marker.command === live.command && JSON.stringify(marker.args) === JSON.stringify(live.args ?? []));
} Type guard
function isClaudeMcpDriftError(e: unknown): boolean {
return e instanceof Error && e.message === "Claude caveman-cloud MCP changed after setup; refusing to overwrite user fields";
} Try / catch
try {
runCavemanSetup();
} catch (e) {
if (isClaudeMcpDriftError(e)) {
// restore the marker-recorded command/args or delete entry+marker and re-run
} else throw e;
} Prevention
- Keep the caveman-cloud entry exactly as caveman wrote it; customize under a different server name
- Re-run caveman setup after intentional manual changes so the journal/marker reflect reality
When it happens
Trigger: Editing the caveman-cloud entry in ~/.claude.json (e.g. changing the binary path or adding args) after Caveman installed it, then running setup/upgrade; or another Caveman version with a different command shape rewrote it without updating the marker.
Common situations: User customizing env or command for a local build; version skew between two caveman installs sharing ~/.claude.json; config sync tools overwriting the entry.
Related errors
- Claude caveman-cloud MCP exists but is not Caveman-journaled
- [mcp_servers.caveman-cloud] exists but is not Caveman-journa
- ${agent} caveman-cloud MCP changed during interrupted setup;
- ${agent} caveman-cloud MCP changed during interrupted remova
- ${file} already exists with non-canonical content; refusing
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/2f18a4e8838e04d1.
Report an issue: GitHub.