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
- Revert your manual caveman-cloud registration changes so recovery can roll back to the journaled state
- Or keep the new registration and clear the pending removal journal, then finish cleanup by hand (skill files, marker)
- 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
- Finish or abort uninstalls before reconfiguring MCP servers
- Manage caveman-cloud exclusively through caveman commands
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
- ${agent} caveman-cloud MCP changed during interrupted setup;
- ${skill.file} changed during interrupted removal; refusing d
- cannot read pending ${agent} agent-native removal journal: $
- could not remove caveman-cloud MCP for ${agent}
- ${skill.file} changed during interrupted setup; refusing des
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/9b6ce1f86cd1ea06.
Report an issue: GitHub.