JuliusBrussee/caveman · error
${file} changed after setup; refusing to overwrite user skil
Error message
${file} changed after setup; refusing to overwrite user skill edits What it means
With a committed bundle journal present, a skill file whose bytes differ from the canonical body AND whose hash does not match the journal's after_sha256 for that file (or has no journal entry at all) is a post-setup user edit. Setup refuses to overwrite it — the user's edits win over the canonical update.
Source
Thrown at packages/cli/src/index.ts:2550
if (status.state !== "installed") repairNativeAgent(agent);
}
function preflightAgentNativeBundleComponents(
agent: "claude" | "codex",
existingBundle: AgentNativeBundleJournal | null,
): void {
const previousSkills = new Map(existingBundle?.skills.map((skill) => [skill.file, skill]) ?? []);
for (const { file, body } of agentNativeSkillFiles(agent)) {
const current = fileBytes(file);
if (!existingBundle) {
if (current && !current.equals(Buffer.from(body))) {
throw new Error(`${file} already exists with non-canonical content; refusing to overwrite an unjournaled skill`);
}
continue;
}
const previous = previousSkills.get(file);
if (current && !current.equals(Buffer.from(body)) && (!previous || bytesHash(current) !== previous.after_sha256)) {
throw new Error(`${file} changed after setup; refusing to overwrite user skill edits`);
}
}
if (agent === "claude") {
const actual = claudeMcpRegistration("caveman-cloud");
const marker = readMcpServerMarker("claude", "caveman-cloud");
if (actual.present && !marker) {
throw new Error("Claude caveman-cloud MCP exists but is not Caveman-journaled; refusing overwrite");
}
if (actual.present && marker && !agentNativeCloudMcpMatches("claude", marker)) {
throw new Error("Claude caveman-cloud MCP changed after setup; refusing to overwrite user fields");
}
return;
}
const config = fileBytes(join(homedir(), ".codex", "config.toml"))?.toString("utf8") ?? "";
if (!config.includes("[mcp_servers.caveman-cloud]")) return;
if (!readMcpServerMarker("codex", "caveman-cloud")) {
throw new Error("[mcp_servers.caveman-cloud] exists but is not Caveman-journaled; refusing overwrite");
}View on GitHub (pinned to 27d5a3981a)
Solutions
- Back up and re-apply your edits: move the edited file aside, re-run setup, then port your changes into the new canonical body
- Or keep your version permanently by renaming the skill directory so future setups treat it as foreign but non-colliding
- Diff your file against the journal's after_sha256/canonical body to confirm which changes are yours
Defensive patterns
Strategy: validation
Validate before calling
function skillUnedited(file: string, journalSha: string | undefined, canonicalBody: Buffer): boolean {
let cur: Buffer;
try { cur = readFileSync(file); } catch { return true; }
if (cur.equals(canonicalBody)) return true;
const h = createHash("sha256").update(cur).digest("hex");
return journalSha !== undefined && h === journalSha;
} Type guard
function isUserEditedSkillError(e: unknown): boolean {
return e instanceof Error && e.message.includes("changed after setup; refusing to overwrite user skill edits");
} Try / catch
try {
runCavemanSetup(); // upgrade path
} catch (e) {
if (isUserEditedSkillError(e)) {
// back up the file, let setup overwrite, re-apply edits to the new body
} else throw e;
} Prevention
- Fork caveman skills under new names instead of editing them in place
- Re-apply customizations after each caveman upgrade rather than blocking it
When it happens
Trigger: Upgrading caveman (new embedded skill bodies) while the user has edited one of the installed skill files since the last setup; or a skill file was added to the suite that now overlaps a user-created file at the same path.
Common situations: User tweaked a Caveman-installed SKILL.md; a pixel convert pass rewrote a body; agent tooling reformatted the file; partial journal missing an entry for a newly introduced skill path.
Related errors
- ${skill.file} changed during interrupted setup; refusing des
- ${agent} caveman-cloud MCP changed during interrupted setup;
- ${skill.file} changed during interrupted removal; refusing d
- ${file} already exists with non-canonical content; refusing
- cannot read ${agent} agent-native bundle journal: ${(error a
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/f525adfcb2ea5ef4.
Report an issue: GitHub.