JuliusBrussee/caveman · error · Error

${agent} caveman-cloud MCP changed during interrupted setup;

Error message

${agent} caveman-cloud MCP changed during interrupted setup; refusing destructive recovery

What it means

The MCP-side guard of interrupted-setup recovery: the on-disk caveman-cloud registration must match the pending target, the recorded previous MCP, or the committed journal's MCP; the marker file (if present) must equally match one of those. If neither holds, the user (or another tool) changed the MCP registration during the interrupted window, and overwriting it would destroy their changes — so recovery refuses.

Source

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

    const currentMatchesBefore = current === null ? before === null : before !== null && bytesHash(current) === bytesHash(before);
    const currentHash = current ? bytesHash(current) : null;
    const currentMatchesCommitted = currentHash !== null && currentHash === committedSkills.get(skill.file);
    if (!currentMatchesBefore && !currentMatchesCommitted && currentHash !== skill.after_sha256) {
      throw new Error(`${skill.file} changed during interrupted setup; refusing destructive recovery`);
    }
  }
  const marker = readMcpServerMarker(agent, "caveman-cloud");
  const markerKnown = !marker
    || sameMcpCommand(marker, pending.cloud_mcp)
    || sameMcpCommand(marker, pending.previous_cloud_mcp)
    || sameMcpCommand(marker, committed?.cloud_mcp ?? null);
  const hostInstalled = agentNativeCloudMcpMatches(agent, pending.cloud_mcp);
  const hostPrevious = pending.previous_cloud_mcp
    ? agentNativeCloudMcpMatches(agent, pending.previous_cloud_mcp)
    : agentNativeCloudMcpHostAbsent(agent);
  const hostCommitted = committed ? agentNativeCloudMcpMatches(agent, committed.cloud_mcp) : false;
  if (!markerKnown || (!hostInstalled && !hostPrevious && !hostCommitted)) {
    throw new Error(`${agent} caveman-cloud MCP changed during interrupted setup; refusing destructive recovery`);
  }
  restoreInstalledAgentNativeBundle(agent, pending);
  unlinkSync(agentNativeBundleJournalPath(agent, true));
  process.stderr.write(`${mark("warn")} completed interrupted ${agent} agent-native bundle before continuing\n`);
}

function skillMatchesBefore(skill: AgentNativeBundleSkill): boolean {
  const current = fileBytes(skill.file);
  const before = skill.before_base64 === null ? null : Buffer.from(skill.before_base64, "base64");
  return current === null ? before === null : before !== null && current.equals(before);
}

function agentNativeCloudMcpHostAbsent(agent: "claude" | "codex"): boolean {
  if (agent === "claude") return !claudeMcpRegistration("caveman-cloud").present;
  const config = fileBytes(join(homedir(), ".codex", "config.toml"))?.toString("utf8") ?? "";
  return !config.includes("[mcp_servers.caveman-cloud]");
}

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Decide which registration you want: either revert your manual caveman-cloud edits so recovery can complete, or keep them and clear the pending journal to abandon the transaction
  2. Re-run setup after resolving — it will either complete or re-journal from the new state
  3. Avoid editing the caveman-cloud MCP entry by hand; use caveman's own install/uninstall commands so markers stay consistent
Defensive patterns

Strategy: validation

Validate before calling

function mcpInKnownState(current: { command: string; args: string[] } | null, options: Array<{ command: string; args: string[] } | null>): boolean {
  return options.some((o) => o && current && current.command === o.command && JSON.stringify(current.args) === JSON.stringify(o.args));
}

Type guard

function isMcpChangedDuringSetupError(e: unknown): boolean {
  return e instanceof Error && e.message.includes("caveman-cloud MCP changed during interrupted setup");
}

Try / catch

try {
  runCavemanAgentCommand("claude");
} catch (e) {
  if (isMcpChangedDuringSetupError(e)) {
    // revert manual caveman-cloud edits or clear the pending journal, then re-run
  } else throw e;
}

Prevention

When it happens

Trigger: Interrupt a setup, then manually edit the caveman-cloud entry in ~/.claude.json (different command/args) or remove it and install a different caveman-cloud server, then run an agent command that triggers recovery.

Common situations: User pointed caveman-cloud at a custom gateway/binary; another caveman version rewrote the registration; the marker file under ~/.caveman-cloud/integrations was deleted or edited while the host config changed.

Related errors


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