JuliusBrussee/caveman · error · Error

cannot read pending ${agent} agent-native removal journal: $

Error message

cannot read pending ${agent} agent-native removal journal: ${(error as Error).message}

What it means

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.

Source

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

      throw new Error("unsupported pending bundle journal");
    }
    return value;
  } catch (error) {
    if ((error as NodeJS.ErrnoException).code === "ENOENT") return null;
    throw new Error(`cannot read pending ${agent} agent-native bundle journal: ${(error as Error).message}`);
  }
}

function readPendingAgentNativeBundleRemoval(agent: "claude" | "codex"): AgentNativeBundleJournal | null {
  try {
    const value = JSON.parse(readFileSync(agentNativeBundleRemovalJournalPath(agent), "utf8")) as AgentNativeBundleJournal;
    if (value.schema_version !== 1 || value.agent !== agent || !value.cloud_mcp || !Array.isArray(value.skills)) {
      throw new Error("unsupported pending bundle removal journal");
    }
    return value;
  } catch (error) {
    if ((error as NodeJS.ErrnoException).code === "ENOENT") return null;
    throw new Error(`cannot read pending ${agent} agent-native removal journal: ${(error as Error).message}`);
  }
}

function readMcpServerMarker(agent: string, serverName: string): { command: string; args: string[] } | null {
  try {
    const value = JSON.parse(readFileSync(mcpServerMarkerPath(agent, serverName), "utf8")) as Record<string, unknown>;
    if (typeof value.command !== "string" || !Array.isArray(value.args) || !value.args.every((arg) => typeof arg === "string")) return null;
    return { command: value.command, args: value.args as string[] };
  } catch {
    return null;
  }
}

function claudeMcpRegistration(serverName: string): { present: boolean; command: string; args: string[]; exact_shape: boolean } {
  const path = join(homedir(), ".claude.json");
  const bytes = fileBytes(path);
  if (!bytes) return { present: false, command: "", args: [], exact_shape: false };
  const root = parseJsonFileObject(path, bytes);

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Inspect ~/.caveman-cloud/integrations/<agent>.agent-native-bundle.removing.json
  2. 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
  3. Delete the malformed removal journal and re-run the uninstall command to rebuild a clean transaction
Defensive patterns

Strategy: try-catch

Validate before calling

function removalJournalIntact(p: string): boolean {
  try {
    const v = JSON.parse(readFileSync(p, "utf8"));
    return v.schema_version === 1 && Array.isArray(v.skills) && !!v.cloud_mcp;
  } catch { return false; }
}

Type guard

function isRemovalJournalReadError(e: unknown): boolean {
  return e instanceof Error && e.message.includes("cannot read pending ") && e.message.includes("removal journal");
}

Try / catch

try {
  runCavemanAgentCommand("claude");
} catch (e) {
  if (isRemovalJournalReadError(e)) {
    // finish or discard the interrupted removal: fix/remove the .removing.json, then re-run
  } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: Uninstall killed by timeout in CI; crash during removal; journal schema changed across CLI versions; disk corruption.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/7bcb3af77c8b9899. Report an issue: GitHub.