{"record":{"id":"9b6ce1f86cd1ea06","repo":"JuliusBrussee/caveman","slug":"agent-caveman-cloud-mcp-changed-during-interrup-9b6ce1","errorCode":null,"errorMessage":"${agent} caveman-cloud MCP changed during interrupted removal; refusing destructive recovery","messagePattern":"(.+?) caveman-cloud MCP changed during interrupted removal; refusing destructive recovery","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":2826,"sourceCode":"    try { unlinkSync(agentNativeBundleJournalPath(agent)); } catch { /* removal already committed */ }\n    unlinkSync(agentNativeBundleRemovalJournalPath(agent));\n    process.stderr.write(`${mark(\"warn\")} completed interrupted ${agent} agent-native bundle removal\\n`);\n    return;\n  }\n  for (const skill of pending.skills) {\n    const current = fileBytes(skill.file);\n    if (current && bytesHash(current) !== skill.after_sha256 && !skillMatchesBefore(skill)) {\n      throw new Error(`${skill.file} changed during interrupted removal; refusing destructive recovery`);\n    }\n  }\n  const marker = readMcpServerMarker(agent, \"caveman-cloud\");\n  const markerKnown = !marker || sameMcpCommand(marker, pending.cloud_mcp) || sameMcpCommand(marker, pending.previous_cloud_mcp);\n  const hostIsInstalled = agentNativeCloudMcpMatches(agent, pending.cloud_mcp);\n  const hostIsPrevious = pending.previous_cloud_mcp\n    ? agentNativeCloudMcpMatches(agent, pending.previous_cloud_mcp)\n    : agentNativeCloudMcpHostAbsent(agent);\n  if (!markerKnown || (!hostIsInstalled && !hostIsPrevious)) {\n    throw new Error(`${agent} caveman-cloud MCP changed during interrupted removal; refusing destructive recovery`);\n  }\n  restoreInstalledAgentNativeBundle(agent, pending);\n  unlinkSync(agentNativeBundleRemovalJournalPath(agent));\n  process.stderr.write(`${mark(\"warn\")} rolled back interrupted ${agent} agent-native bundle removal before continuing\\n`);\n}\n\nfunction preflightAgentNativeSetup(agent: \"claude\" | \"codex\"): void {\n  recoverPendingAgentNativeRemoval(agent);\n  recoverPendingAgentNativeBundle(agent);\n  const profile = findAgent(agent)!;\n  if (!which(binOf(profile))) throw new Error(`${profile.display_name} not found on PATH`);\n  const mcpBinary = nativeMcpBinaryRequired();\n  const gw = gatewayURL();\n  nativeProxyBinaryRequired(gw);\n  withIntegrationLock(agent, () => recoverPendingNativeInstallUnlocked(agent));\n  const status = nativeIntegrationStatus(agent);\n  if (!status.installed) nativeMutationsFor(agent, gw, mcpBinary);\n}","sourceCodeStart":2808,"sourceCodeEnd":2844,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/cli/src/index.ts#L2808-L2844","documentation":"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.","triggerScenarios":"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).","commonSituations":"User re-added caveman-cloud MCP manually with a different command; another installer rewrote the entry; partial update changed the binary path.","solutions":["Restore the MCP entry to the command recorded in the removal journal's cloud_mcp/previous_cloud_mcp","Delete the pending removal journal if you accept the current MCP configuration as-is","Manually complete or cancel the removal, then re-run setup"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const marker = readMcpServerMarker(agent, 'caveman-cloud');\nconst ok = !marker || sameMcpCommand(marker, journal.cloud_mcp) || sameMcpCommand(marker, journal.previous_cloud_mcp);\nif (!ok) console.error('caveman-cloud MCP entry no longer matches removal journal; resolve before retry.');","typeGuard":null,"tryCatchPattern":"try {\n  runSetup(agent);\n} catch (e) {\n  if (String(e.message).includes('MCP changed during interrupted removal')) {\n    // restore the recorded command or accept current config by deleting the removal journal\n  }\n}","preventionTips":["Avoid manual edits to the caveman-cloud MCP section during a pending removal","Do not run competing installers for the same MCP server name","Check for pending journals before reconfiguring agent MCPs"],"tags":["journal-integrity","mcp-config","recovery","cli"],"backgroundTag":"checksum-mismatch","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}