JuliusBrussee/caveman · error

[mcp_servers.caveman-cloud] exists but is not Caveman-journa

Error message

[mcp_servers.caveman-cloud] exists but is not Caveman-journaled; refusing overwrite

What it means

Codex-specific preflight: ~/.codex/config.toml contains a [mcp_servers.caveman-cloud] table, but no Caveman marker file exists for it. As with the Claude case, an unjournaled registration has unknown provenance and Caveman refuses to overwrite it during agent-native setup.

Source

Thrown at packages/cli/src/index.ts:2567

    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,
      after_sha256: bytesHash(Buffer.from(body)),
    };
  });
}

function verifyAgentNativeBundle(agent: "claude" | "codex", journal: AgentNativeBundleJournal, cloudMcp: { command: string; args: string[] }): void {
  const status = nativeIntegrationStatus(agent);

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Remove the [mcp_servers.caveman-cloud] table from ~/.codex/config.toml and re-run setup so Caveman installs and journals it
  2. Or rename your custom table to a different server key if you want to keep it
  3. Check CODEX_HOME is set as intended so setup reads/writes the config you actually use
Defensive patterns

Strategy: validation

Validate before calling

function codexCavemanCloudJournaled(): boolean {
  const toml = readFileSync(join(homedir(), ".codex", "config.toml"), "utf8");
  if (!toml.includes("[mcp_servers.caveman-cloud]")) return true;
  return existsSync(join(cavemanHome(), "mcp", "codex.caveman-cloud.json"));
}

Type guard

function isUnjournaledCodexMcpError(e: unknown): boolean {
  return e instanceof Error && e.message === "[mcp_servers.caveman-cloud] exists but is not Caveman-journaled; refusing overwrite";
}

Try / catch

try {
  runCavemanSetup();
} catch (e) {
  if (isUnjournaledCodexMcpError(e)) {
    // delete the [mcp_servers.caveman-cloud] table (or rename its key), then re-run
  } else throw e;
}

Prevention

When it happens

Trigger: Manually adding [mcp_servers.caveman-cloud] to ~/.codex/config.toml; using a pre-marker Caveman version; CODEX_HOME pointing at a config that already had the table; deleting ~/.caveman-cloud/integrations markers.

Common situations: Hand-edited codex config; config restored/synced without the caveman home; leftover from an older caveman release.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/978a46ae0480a16b. Report an issue: GitHub.