{"record":{"id":"fcb6810b62d1891e","repo":"JuliusBrussee/caveman","slug":"agent-caveman-cloud-mcp-changed-during-interrup","errorCode":null,"errorMessage":"${agent} caveman-cloud MCP changed during interrupted setup; refusing destructive recovery","messagePattern":"(.+?) caveman-cloud MCP changed during interrupted setup; refusing destructive recovery","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":2763,"sourceCode":"    const currentMatchesBefore = current === null ? before === null : before !== null && bytesHash(current) === bytesHash(before);\n    const currentHash = current ? bytesHash(current) : null;\n    const currentMatchesCommitted = currentHash !== null && currentHash === committedSkills.get(skill.file);\n    if (!currentMatchesBefore && !currentMatchesCommitted && currentHash !== skill.after_sha256) {\n      throw new Error(`${skill.file} changed during interrupted setup; refusing destructive recovery`);\n    }\n  }\n  const marker = readMcpServerMarker(agent, \"caveman-cloud\");\n  const markerKnown = !marker\n    || sameMcpCommand(marker, pending.cloud_mcp)\n    || sameMcpCommand(marker, pending.previous_cloud_mcp)\n    || sameMcpCommand(marker, committed?.cloud_mcp ?? null);\n  const hostInstalled = agentNativeCloudMcpMatches(agent, pending.cloud_mcp);\n  const hostPrevious = pending.previous_cloud_mcp\n    ? agentNativeCloudMcpMatches(agent, pending.previous_cloud_mcp)\n    : agentNativeCloudMcpHostAbsent(agent);\n  const hostCommitted = committed ? agentNativeCloudMcpMatches(agent, committed.cloud_mcp) : false;\n  if (!markerKnown || (!hostInstalled && !hostPrevious && !hostCommitted)) {\n    throw new Error(`${agent} caveman-cloud MCP changed during interrupted setup; refusing destructive recovery`);\n  }\n  restoreInstalledAgentNativeBundle(agent, pending);\n  unlinkSync(agentNativeBundleJournalPath(agent, true));\n  process.stderr.write(`${mark(\"warn\")} completed interrupted ${agent} agent-native bundle before continuing\\n`);\n}\n\nfunction skillMatchesBefore(skill: AgentNativeBundleSkill): boolean {\n  const current = fileBytes(skill.file);\n  const before = skill.before_base64 === null ? null : Buffer.from(skill.before_base64, \"base64\");\n  return current === null ? before === null : before !== null && current.equals(before);\n}\n\nfunction agentNativeCloudMcpHostAbsent(agent: \"claude\" | \"codex\"): boolean {\n  if (agent === \"claude\") return !claudeMcpRegistration(\"caveman-cloud\").present;\n  const config = fileBytes(join(codexHomeDir(), \"config.toml\"))?.toString(\"utf8\") ?? \"\";\n  return !config.includes(\"[mcp_servers.caveman-cloud]\");\n}\n","sourceCodeStart":2745,"sourceCodeEnd":2781,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/cli/src/index.ts#L2745-L2781","documentation":"When recovering an interrupted agent-native bundle setup, the CLI checks that the caveman-cloud MCP registration in the agent's native config matches one of the known states (the pending config, the previous config, or the committed config), or is covered by a marker. If the marker is unknown and the host registration matches none of them, someone or something changed the MCP entry outside the journal, so destructive recovery is refused.","triggerScenarios":"Re-running setup after an interrupted run where the agent's native MCP config entry for caveman-cloud was edited manually, replaced by another installer, or the journal's marker file was deleted/does not match.","commonSituations":"User hand-edited claude_desktop_config.json / codex config.toml; another tool reinstalled the MCP server with a different command; a partially applied update changed the server command line.","solutions":["Restore the caveman-cloud MCP entry in the agent config to the command recorded in pending.cloud_mcp or previous_cloud_mcp","Delete the pending bundle journal if you accept the current MCP registration and want a clean re-setup","Re-run setup so the interrupted bundle completes and the journal is consumed"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const marker = readMcpServerMarker(agent, 'caveman-cloud');\nconst reg = readAgentMcpConfig(agent).find(s => s.name === 'caveman-cloud');\nif (reg && marker && !sameMcpCommand(reg, marker)) console.error('MCP entry diverged from marker; restore before setup.');","typeGuard":null,"tryCatchPattern":"try {\n  runSetup(agent);\n} catch (e) {\n  if (String(e.message).includes('MCP changed during interrupted setup')) {\n    // restore the recorded cloud_mcp command or delete the pending journal deliberately\n  }\n}","preventionTips":["Never hand-edit the caveman-cloud MCP entry in agent configs","Let the CLI complete or roll back interrupted setups before editing configs","Keep journal/marker files intact — do not clean them with temp-file cleaners"],"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"}