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

  1. Back up and re-apply your edits: move the edited file aside, re-run setup, then port your changes into the new canonical body
  2. Or keep your version permanently by renaming the skill directory so future setups treat it as foreign but non-colliding
  3. 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

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


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