JuliusBrussee/caveman · error

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

Error message

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

What it means

removeAgentNativeBundle failed partway (error in the try block), but the compensating restoreInstalledAgentNativeBundle succeeded: the installed bundle was put back and the removal journal cleaned up. State is back to installed; only the removal attempt itself failed.

Source

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

    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=")
    && argv[index - 1] !== "--agent-native");
  if (unknown.length > 0 || (hasAgentNativeFlag && !agentNative) || (agentNative && (json || install)) || (removeBundle && !agentNative)) {

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Read the embedded original error message — it names the failing step; address it (close agent, fix permissions)
  2. Re-run `caveman setup --agent-native <agent> --remove` once the blocking condition is gone
  3. If it persists, run setup again to normalize the bundle, then remove
Defensive patterns

Strategy: retry

Validate before calling

import { accessSync, constants } from "node:fs";
accessSync(join(homedir(), agentConfigName(agent)), constants.W_OK);  // throws early if unwritable

Try / catch

try {
  await setup(["--agent-native", agent, "--remove"]);
} catch (error) {
  const msg = (error as Error).message;
  if (/installed bundle restored/.test(msg)) {
    // state is safely back to installed; the embedded original error is the actionable part
    await resolveOriginalFailure(extractOriginal(msg));   // e.g. close agent
    await setup(["--agent-native", agent, "--remove"]);   // safe to retry once
  } else throw error;
}

Prevention

When it happens

Trigger: Running --remove when one step (skill restore, MCP restore, native disable, or journal unlink) fails while the rest of the environment is healthy enough to restore the bundle.

Common situations: Transient failure such as a config file momentarily locked by the agent; a single skill path unwritable; then the agent exits and restore succeeds.

Related errors


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