JuliusBrussee/caveman · error · Error

caveman-cloud MCP changed during interrupted removal…

Error message

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

What it means

When rolling back an interrupted removal, the CLI verifies the caveman-cloud MCP registration in the agent's native config still matches the pending removal's recorded command or the previous command (or the marker is unknown/absent). If it matches neither, the entry was changed externally and rollback would overwrite a foreign configuration, so it throws.

Solutions

  1. Restore the MCP entry to the command recorded in the removal journal's cloud_mcp/previous_cloud_mcp
  2. Delete the pending removal journal if you accept the current MCP configuration as-is
  3. Manually complete or cancel the removal, then re-run setup
Defensive patterns

Strategy: validation

Validate before calling

const marker = readMcpServerMarker(agent, 'caveman-cloud');
const ok = !marker || sameMcpCommand(marker, journal.cloud_mcp) || sameMcpCommand(marker, journal.previous_cloud_mcp);
if (!ok) console.error('caveman-cloud MCP entry no longer matches removal journal; resolve before retry.');

Try / catch

try {
  runSetup(agent);
} catch (e) {
  if (String(e.message).includes('MCP changed during interrupted removal')) {
    // restore the recorded command or accept current config by deleting the removal journal
  }
}

Prevention

When it happens

Trigger: Re-running setup while a pending removal journal exists and the agent's caveman-cloud MCP command differs from both pending.cloud_mcp and pending.previous_cloud_mcp (or, when no previous is recorded, the host is not absent as expected).

Common situations: User re-added caveman-cloud MCP manually with a different command; another installer rewrote the entry; partial update changed the binary path.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/9b6ce1f86cd1ea06. Report an issue: GitHub.

Appendix: source

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

    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 3ee70a1026)