JuliusBrussee/caveman · error · Error

${agent} caveman-cloud MCP changed during interrupted remova

Error message

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

What it means

The MCP guard of interrupted-removal recovery: the host caveman-cloud registration must match the journaled cloud_mcp or previous_cloud_mcp, and any marker file must match one of those. A registration that matches neither means it changed during the interrupted removal, so rolling back (restoring the installed bundle) would clobber the new state — recovery refuses instead.

Source

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

    try { unlinkSync(agentNativeBundleJournalPath(agent)); } catch { /* removal already committed */ }
    unlinkSync(agentNativeBundleRemovalJournalPath(agent));
    process.stderr.write(`${mark("warn")} completed interrupted ${agent} agent-native bundle removal\n`);
    return;
  }
  for (const skill of pending.skills) {
    const current = fileBytes(skill.file);
    if (current && bytesHash(current) !== skill.after_sha256 && !skillMatchesBefore(skill)) {
      throw new Error(`${skill.file} changed during interrupted removal; refusing destructive recovery`);
    }
  }
  const marker = readMcpServerMarker(agent, "caveman-cloud");
  const markerKnown = !marker || sameMcpCommand(marker, pending.cloud_mcp) || sameMcpCommand(marker, pending.previous_cloud_mcp);
  const hostIsInstalled = agentNativeCloudMcpMatches(agent, pending.cloud_mcp);
  const hostIsPrevious = pending.previous_cloud_mcp
    ? agentNativeCloudMcpMatches(agent, pending.previous_cloud_mcp)
    : agentNativeCloudMcpHostAbsent(agent);
  if (!markerKnown || (!hostIsInstalled && !hostIsPrevious)) {
    throw new Error(`${agent} caveman-cloud MCP changed during interrupted removal; refusing destructive recovery`);
  }
  restoreInstalledAgentNativeBundle(agent, pending);
  unlinkSync(agentNativeBundleRemovalJournalPath(agent));
  process.stderr.write(`${mark("warn")} rolled back interrupted ${agent} agent-native bundle removal before continuing\n`);
}

function preflightAgentNativeSetup(agent: "claude" | "codex"): void {
  recoverPendingAgentNativeRemoval(agent);
  recoverPendingAgentNativeBundle(agent);
  const profile = findAgent(agent)!;
  if (!which(binOf(profile))) throw new Error(`${profile.display_name} not found on PATH`);
  const mcpBinary = nativeMcpBinaryRequired();
  const gw = gatewayURL();
  nativeProxyBinaryRequired(gw);
  withIntegrationLock(agent, () => recoverPendingNativeInstallUnlocked(agent));
  const status = nativeIntegrationStatus(agent);
  if (!status.installed) nativeMutationsFor(agent, gw, mcpBinary);
}

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Revert your manual caveman-cloud registration changes so recovery can roll back to the journaled state
  2. Or keep the new registration and clear the pending removal journal, then finish cleanup by hand (skill files, marker)
  3. Use caveman's own install/uninstall verbs rather than editing MCP entries directly
Defensive patterns

Strategy: validation

Validate before calling

function removalMcpSafe(current: { command: string; args: string[] } | null, pending: { cloud_mcp: { command: string; args: string[] }; previous_cloud_mcp: { command: string; args: string[] } | null }): boolean {
  const same = (a: { command: string; args: string[] } | null, b: { command: string; args: string[] } | null) =>
    !!a && !!b && a.command === b.command && JSON.stringify(a.args) === JSON.stringify(b.args);
  return same(current, pending.cloud_mcp) || same(current, pending.previous_cloud_mcp);
}

Type guard

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

Try / catch

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

Prevention

When it happens

Trigger: Interrupt an uninstall, then hand-edit or replace the caveman-cloud MCP entry (or delete it and add a different one), then run an agent command that triggers removal recovery.

Common situations: User reinstalled or reconfigured caveman-cloud manually; ran another caveman version's setup in the gap; deleted the marker file while changing the host registration.

Related errors


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