{"record":{"id":"7bcb3af77c8b9899","repo":"JuliusBrussee/caveman","slug":"cannot-read-pending-agent-agent-native-removal","errorCode":null,"errorMessage":"cannot read pending ${agent} agent-native removal journal: ${(error as Error).message}","messagePattern":"cannot read pending (.+?) agent-native removal journal: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":2322,"sourceCode":"      throw new Error(\"unsupported pending bundle journal\");\n    }\n    return value;\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n    throw new Error(`cannot read pending ${agent} agent-native bundle journal: ${(error as Error).message}`);\n  }\n}\n\nfunction readPendingAgentNativeBundleRemoval(agent: \"claude\" | \"codex\"): AgentNativeBundleJournal | null {\n  try {\n    const value = JSON.parse(readFileSync(agentNativeBundleRemovalJournalPath(agent), \"utf8\")) as AgentNativeBundleJournal;\n    if (value.schema_version !== 1 || value.agent !== agent || !value.cloud_mcp || !Array.isArray(value.skills)) {\n      throw new Error(\"unsupported pending bundle removal journal\");\n    }\n    return value;\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n    throw new Error(`cannot read pending ${agent} agent-native removal journal: ${(error as Error).message}`);\n  }\n}\n\nfunction readMcpServerMarker(agent: string, serverName: string): { command: string; args: string[] } | null {\n  try {\n    const value = JSON.parse(readFileSync(mcpServerMarkerPath(agent, serverName), \"utf8\")) as Record<string, unknown>;\n    if (typeof value.command !== \"string\" || !Array.isArray(value.args) || !value.args.every((arg) => typeof arg === \"string\")) return null;\n    return { command: value.command, args: value.args as string[] };\n  } catch {\n    return null;\n  }\n}\n\nfunction claudeMcpRegistration(serverName: string): { present: boolean; command: string; args: string[]; exact_shape: boolean } {\n  const path = join(homedir(), \".claude.json\");\n  const bytes = fileBytes(path);\n  if (!bytes) return { present: false, command: \"\", args: [], exact_shape: false };\n  const root = parseJsonFileObject(path, bytes);","sourceCodeStart":2304,"sourceCodeEnd":2340,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/cli/src/index.ts#L2304-L2340","documentation":"readPendingAgentNativeBundleRemoval() reads the '.removing' journal that records an in-flight uninstall of the agent-native bundle. Like its siblings, only ENOENT is tolerated; corrupt JSON or a shape that fails validation (schema_version, agent match, cloud_mcp presence, skills array) is rethrown with this message, blocking removal recovery.","triggerScenarios":"An interrupted `caveman setup` removal/uninstall step (killed between journaling and commit) leaves a malformed .agent-native-bundle.removing.json; a subsequent agent command triggers recoverPendingAgentNativeRemoval which fails to parse it.","commonSituations":"Uninstall killed by timeout in CI; crash during removal; journal schema changed across CLI versions; disk corruption.","solutions":["Inspect ~/.caveman-cloud/integrations/<agent>.agent-native-bundle.removing.json","If the removal was nearly complete, finish it manually (delete the skills dirs and MCP entry the journal lists) and remove the journal, or restore from the committed journal","Delete the malformed removal journal and re-run the uninstall command to rebuild a clean transaction"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"function removalJournalIntact(p: string): boolean {\n  try {\n    const v = JSON.parse(readFileSync(p, \"utf8\"));\n    return v.schema_version === 1 && Array.isArray(v.skills) && !!v.cloud_mcp;\n  } catch { return false; }\n}","typeGuard":"function isRemovalJournalReadError(e: unknown): boolean {\n  return e instanceof Error && e.message.includes(\"cannot read pending \") && e.message.includes(\"removal journal\");\n}","tryCatchPattern":"try {\n  runCavemanAgentCommand(\"claude\");\n} catch (e) {\n  if (isRemovalJournalReadError(e)) {\n    // finish or discard the interrupted removal: fix/remove the .removing.json, then re-run\n  } else throw e;\n}","preventionTips":["Do not kill uninstall mid-way; if you must, re-run it promptly to let recovery settle","Treat ~/.caveman-cloud/integrations/*.removing.json as transaction files — never edit or partially copy them","Keep backups of the agent config when experimenting with interrupted installs"],"tags":["journal","recovery","uninstall","agent-native"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}