{"record":{"id":"a3ddf29de09ee5ed","repo":"JuliusBrussee/caveman","slug":"file-already-exists-with-non-canonical-content","errorCode":null,"errorMessage":"${file} already exists with non-canonical content; refusing to overwrite an unjournaled skill","messagePattern":"(.+?) already exists with non-canonical content; refusing to overwrite an unjournaled skill","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":2544,"sourceCode":"function ensureAgentNativeIntegration(agent: \"claude\" | \"codex\"): void {\n  const status = nativeIntegrationStatus(agent);\n  if (!status.installed) {\n    enableNative([agent]);\n    return;\n  }\n  if (status.state !== \"installed\") repairNativeAgent(agent);\n}\n\nfunction preflightAgentNativeBundleComponents(\n  agent: \"claude\" | \"codex\",\n  existingBundle: AgentNativeBundleJournal | null,\n): void {\n  const previousSkills = new Map(existingBundle?.skills.map((skill) => [skill.file, skill]) ?? []);\n  for (const { file, body } of agentNativeSkillFiles(agent)) {\n    const current = fileBytes(file);\n    if (!existingBundle) {\n      if (current && !current.equals(Buffer.from(body))) {\n        throw new Error(`${file} already exists with non-canonical content; refusing to overwrite an unjournaled skill`);\n      }\n      continue;\n    }\n    const previous = previousSkills.get(file);\n    if (current && !current.equals(Buffer.from(body)) && (!previous || bytesHash(current) !== previous.after_sha256)) {\n      throw new Error(`${file} changed after setup; refusing to overwrite user skill edits`);\n    }\n  }\n  if (agent === \"claude\") {\n    const actual = claudeMcpRegistration(\"caveman-cloud\");\n    const marker = readMcpServerMarker(\"claude\", \"caveman-cloud\");\n    if (actual.present && !marker) {\n      throw new Error(\"Claude caveman-cloud MCP exists but is not Caveman-journaled; refusing overwrite\");\n    }\n    if (actual.present && marker && !agentNativeCloudMcpMatches(\"claude\", marker)) {\n      throw new Error(\"Claude caveman-cloud MCP changed after setup; refusing to overwrite user fields\");\n    }\n    return;","sourceCodeStart":2526,"sourceCodeEnd":2562,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/cli/src/index.ts#L2526-L2562","documentation":"In preflightAgentNativeBundleComponents with no existing bundle journal, a skill file that already exists on disk but does not byte-equal the canonical embedded body is treated as foreign user content. Since there is no journal to prove Caveman wrote it, overwriting would destroy someone else's work — hence the refusal.","triggerScenarios":"Running agent-native setup when ~/.claude/skills/<name>/SKILL.md (or the codex equivalent) already exists from an older Caveman version with a different body, or was created by the user/another tool with the same name.","commonSituations":"Name collision between Caveman's agent-native suite and a user skill; leftover files from a manual install or a previous CLI version whose embedded bodies changed; a different product's skill with the same directory name.","solutions":["If the existing file is yours, back it up and move it away (or rename its directory), then re-run setup","If it is a stale Caveman artifact from an unjournaled older install, verify and delete it so setup can write the canonical body","If you want to keep a customized version, maintain it under a different skill name so it cannot collide"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"function skillPathIsFreeOrCanonical(file: string, canonicalBody: Buffer): boolean {\n  try {\n    const cur = readFileSync(file);\n    return cur.equals(canonicalBody);\n  } catch { return true; } // absent = fine\n}","typeGuard":"function isUnjournaledSkillError(e: unknown): boolean {\n  return e instanceof Error && e.message.includes(\"already exists with non-canonical content\");\n}","tryCatchPattern":"try {\n  runCavemanSetup();\n} catch (e) {\n  if (isUnjournaledSkillError(e)) {\n    // message names the file — back it up, move it away, re-run\n  } else throw e;\n}","preventionTips":["Avoid naming your own skills identically to caveman's agent-native suite","Move personalized skills to distinct directories before setup"],"tags":["skills","install","safety","preflight"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}