JuliusBrussee/caveman · critical

agent-native bundle removal failed: ${(error as Error).messa

Error message

agent-native bundle removal failed: ${(error as Error).message}; rollback incomplete: ${(rollback as Error).message}

What it means

Worst-case outcome of removeAgentNativeBundle: the removal sequence (restore skills, restore previous cloud MCP, disable native agent, unlink journals) threw, AND the compensating rollback (restoreInstalledAgentNativeBundle + unlink of the removal journal) also threw. The system is now in an unknown partially-removed state and the removal journal file remains on disk for recovery.

Source

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

  if (journal.native_owned) {
    const nativeJournal = readNativeJournal(agent);
    if (nativeJournal) {
      for (const operation of nativeJournal.operations) restoreNativeOperation(operation);
    }
  }
  atomicWriteFile(agentNativeBundleRemovalJournalPath(agent), Buffer.from(JSON.stringify(journal, null, 2) + "\n"));
  try {
    restoreAgentNativeBundleSkills(journal.skills);
    restoreAgentNativeCloudMcp(agent, journal.previous_cloud_mcp);
    if (journal.native_owned) disableNativeAgent(agent);
    unlinkSync(agentNativeBundleJournalPath(agent));
    unlinkSync(agentNativeBundleRemovalJournalPath(agent));
  } catch (error) {
    try {
      restoreInstalledAgentNativeBundle(agent, journal);
      unlinkSync(agentNativeBundleRemovalJournalPath(agent));
    } catch (rollback) {
      throw new Error(`agent-native bundle removal failed: ${(error as Error).message}; rollback incomplete: ${(rollback as Error).message}`);
    }
    throw new Error(`agent-native bundle removal failed: ${(error as Error).message}; installed bundle restored`);
  }
  process.stderr.write(`${mark("ok")} ${agent}: agent-native bundle removed; prior skills and cloud MCP restored\n`);
}

async function setup(argv: string[] = []) {
  const json = argv.includes("--json");
  const install = argv.includes("--install");
  const removeBundle = argv.includes("--remove");
  const agentNative = flagFrom(argv, "--agent-native", "");
  const hasAgentNativeFlag = argv.includes("--agent-native") || argv.some((arg) => arg.startsWith("--agent-native="));
  const unknown = argv.filter((arg, index) =>
    arg !== "--json"
    && arg !== "--install"
    && arg !== "--remove"
    && arg !== "--agent-native"
    && !arg.startsWith("--agent-native=")

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Fix the underlying filesystem problem named in the rollback message (permissions, disk space, locked file)
  2. Close the running agent, then re-run `caveman setup --agent-native <agent> --remove`; recoverPendingAgentNativeRemoval picks up the on-disk removal journal
  3. If recovery loops, remove the bundle journal and agent-native entries manually after backing up the agent config
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight for --remove: agent not running, config writable
import { accessSync, constants } from "node:fs";
accessSync(agentConfigPath, constants.W_OK);
if (await isProcessRunning(agentBinaryName)) throw new Error(`close ${agentBinaryName} before bundle removal`);

Try / catch

try {
  await setup(["--agent-native", agent, "--remove"]);
} catch (error) {
  if (/rollback incomplete/.test((error as Error).message)) {
    // do NOT retry blindly; the removal journal on disk is the recovery point.
    // fix the filesystem condition named in the message, then re-run --remove:
    // recoverPendingAgentNativeRemoval completes or restarts the removal.
    logAndPageOncall(error);   // state is partially removed; needs operator attention
  } else throw error;
}

Prevention

When it happens

Trigger: Running --remove when filesystem operations fail mid-sequence: permission loss, skills directory removed externally, config path unwritable — and the restore-back attempt hits the same filesystem problem.

Common situations: Agent config file locked by a running agent (Windows/locked-file semantics); read-only home directory; disk full; skills directory deleted by hand while the journal still references it.

Related errors


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