JuliusBrussee/caveman · error · Error
changed during interrupted removal; refusing destructive…
Error message
${skill.file} changed during interrupted removal; refusing destructive recovery What it means
During recovery of an interrupted agent-native bundle REMOVAL, each journaled skill file is checked to still match its post-setup hash (after_sha256) or its pre-setup content. If the file differs from both, it was modified after setup, and the removal rollback would destroy unknown content, so the CLI refuses.
Solutions
- Restore the skill file content to match the journal's after_sha256 (re-download or re-copy the canonical skill)
- Delete the pending removal journal if you accept losing the current file content
- Skip rollback by manually deleting the journaled files and the journal yourself
Defensive patterns
Strategy: validation
Validate before calling
for (const skill of journal.skills) {
const cur = existsSync(skill.file) ? readFileSync(skill.file) : null;
if (cur && createHash('sha256').update(cur).digest('hex') !== skill.after_sha256) {
console.error(`${skill.file} differs from journaled state; resolve before removal retry.`);
}
} Try / catch
try {
runSetup(agent);
} catch (e) {
if (String(e.message).includes('changed during interrupted removal')) {
// back up the divergent file, restore journaled content or delete journal explicitly
}
} Prevention
- Treat Caveman-installed skill files as managed: edit copies, not originals
- Complete interrupted removals promptly
- Version-control your custom skills outside the managed directory
When it happens
Trigger: Running setup/removal while a pending removal journal exists and a skill file's current bytes neither hash to after_sha256 nor match the before snapshot (skillMatchesBefore).
Common situations: User edited a Caveman-installed skill file themselves, then removal was interrupted and retried; a formatter or sync tool rewrote the file between interruption and retry.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- changed during interrupted setup; refusing destructive…
- caveman-cloud MCP changed during interrupted setup…
- caveman-cloud MCP changed during interrupted removal…
- already exists with non-canonical content; refusing to…
- changed after setup; refusing to overwrite user skill edits
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/21408c8e09171ac4.
Report an issue: GitHub.
Appendix: source
Thrown at packages/cli/src/index.ts:2816
installAgentNativeCloudMcp(agent, journal.cloud_mcp);
installAgentNativeBundleSkills(agent, journal);
verifyAgentNativeBundle(agent, journal, journal.cloud_mcp);
atomicWriteFile(agentNativeBundleJournalPath(agent), Buffer.from(JSON.stringify(journal, null, 2) + "\n"));
}
function recoverPendingAgentNativeRemoval(agent: "claude" | "codex"): void {
const pending = readPendingAgentNativeBundleRemoval(agent);
if (!pending) return;
if (agentNativeBundleRemovalCompleted(agent, pending)) {
try { unlinkSync(agentNativeBundleJournalPath(agent)); } catch { /* removal already committed */ }
unlinkSync(agentNativeBundleRemovalJournalPath(agent));
process.stderr.write(`${mark("warn")} completed interrupted ${agent} agent-native bundle removal\n`);
return;
}
for (const skill of pending.skills) {
const current = fileBytes(skill.file);
if (current && bytesHash(current) !== skill.after_sha256 && !skillMatchesBefore(skill)) {
throw new Error(`${skill.file} changed during interrupted removal; refusing destructive recovery`);
}
}
const marker = readMcpServerMarker(agent, "caveman-cloud");
const markerKnown = !marker || sameMcpCommand(marker, pending.cloud_mcp) || sameMcpCommand(marker, pending.previous_cloud_mcp);
const hostIsInstalled = agentNativeCloudMcpMatches(agent, pending.cloud_mcp);
const hostIsPrevious = pending.previous_cloud_mcp
? agentNativeCloudMcpMatches(agent, pending.previous_cloud_mcp)
: agentNativeCloudMcpHostAbsent(agent);
if (!markerKnown || (!hostIsInstalled && !hostIsPrevious)) {
throw new Error(`${agent} caveman-cloud MCP changed during interrupted removal; refusing destructive recovery`);
}
restoreInstalledAgentNativeBundle(agent, pending);
unlinkSync(agentNativeBundleRemovalJournalPath(agent));
process.stderr.write(`${mark("warn")} rolled back interrupted ${agent} agent-native bundle removal before continuing\n`);
}
function preflightAgentNativeSetup(agent: "claude" | "codex"): void {
recoverPendingAgentNativeRemoval(agent);View on GitHub (pinned to 3ee70a1026)