JuliusBrussee/caveman · error
Claude caveman-cloud MCP exists but is not Caveman-journaled
Error message
Claude caveman-cloud MCP exists but is not Caveman-journaled; refusing overwrite
What it means
Claude-specific preflight: claudeMcpRegistration('caveman-cloud') finds a caveman-cloud entry in ~/.claude.json, but no Caveman marker file exists under ~/.caveman-cloud/integrations proving Caveman installed it. Without the marker, Caveman cannot know the entry's provenance or safely overwrite it, so setup refuses rather than clobber a possibly user-owned registration.
Source
Thrown at packages/cli/src/index.ts:2557
const previousSkills = new Map(existingBundle?.skills.map((skill) => [skill.file, skill]) ?? []);
for (const { file, body } of agentNativeSkillFiles(agent)) {
const current = fileBytes(file);
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));View on GitHub (pinned to 27d5a3981a)
Solutions
- If you do not need the manual entry, remove caveman-cloud from ~/.claude.json's mcpServers and re-run setup so Caveman installs and journals it
- If you want to keep your custom entry, rename it to something other than caveman-cloud so Caveman can own the canonical name
- Never delete ~/.caveman-cloud/integrations markers while keeping host registrations
Defensive patterns
Strategy: validation
Validate before calling
import { existsSync, readFileSync } from "node:fs";
function claudeCavemanCloudJournaled(): boolean {
const cfg = JSON.parse(readFileSync(join(homedir(), ".claude.json"), "utf8"));
const present = !!cfg.mcpServers?.["caveman-cloud"];
const marker = existsSync(join(cavemanHome(), "mcp", "claude.caveman-cloud.json"));
return !present || marker;
} Type guard
function isUnjournaledClaudeMcpError(e: unknown): boolean {
return e instanceof Error && e.message === "Claude caveman-cloud MCP exists but is not Caveman-journaled; refusing overwrite";
} Try / catch
try {
runCavemanSetup();
} catch (e) {
if (isUnjournaledClaudeMcpError(e)) {
// remove the manual caveman-cloud entry from ~/.claude.json (or rename it), re-run
} else throw e;
} Prevention
- Never hand-add a caveman-cloud server to Claude's config — let caveman install it
- Do not delete ~/.caveman-cloud/integrations markers while keeping host registrations
When it happens
Trigger: User (or an old Caveman version that did not write markers) manually added a caveman-cloud server to Claude's mcpServers; marker files were deleted from ~/.caveman-cloud/integrations; home dir restored from backup without the marker.
Common situations: Hand-written MCP config copied from docs or a teammate; leftover from a pre-marker CLI version; cleaning ~/.caveman-cloud while keeping ~/.claude.json.
Related errors
- Claude caveman-cloud MCP changed after setup; refusing to ov
- [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/528246b888948013.
Report an issue: GitHub.