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
- Fix the underlying filesystem problem named in the rollback message (permissions, disk space, locked file)
- Close the running agent, then re-run `caveman setup --agent-native <agent> --remove`; recoverPendingAgentNativeRemoval picks up the on-disk removal journal
- 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
- Always close the agent before --remove to avoid locked config files
- Keep the removal journal path writable; it is the crash-recovery record
- Monitor free disk space and home-directory permissions before destructive ops
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
- cave_harness_aborted
- cave_vercel_terminal_failure
- caveman agent: invalid .caveman/provider.json
- lock disappeared during validation
- caveman-code: not a file: ${input.path}
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/1c90ecb758ec9e83.
Report an issue: GitHub.