{"record":{"id":"e6a5a553e27fb148","repo":"vercel/ai","slug":"duplicate-cline-skill-name-skill-name","errorCode":null,"errorMessage":"Duplicate Cline skill name: ${skill.name}","messagePattern":"Duplicate Cline skill name: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/harness-cline/src/cline-skills.ts","lineNumber":99,"sourceCode":"\nfunction projectClineSkills({\n  skills,\n}: {\n  skills: ReadonlyArray<HarnessV1Skill>;\n}): ReadonlyArray<ProjectedClineSkill> {\n  const names = new Set<string>();\n  const ids = new Set<string>();\n  return skills\n    .map(skill => {\n      if (\n        !CLINE_SKILL_NAME_PATTERN.test(skill.name) ||\n        skill.name === '.' ||\n        skill.name === '..'\n      ) {\n        throw new Error(`Invalid Cline skill name: ${skill.name}`);\n      }\n      if (names.has(skill.name)) {\n        throw new Error(`Duplicate Cline skill name: ${skill.name}`);\n      }\n      names.add(skill.name);\n\n      const id = normalizeSkillToken(skill.name);\n      if (ids.has(id)) {\n        throw new Error(`Duplicate Cline skill identifier: ${id}`);\n      }\n      ids.add(id);\n\n      return {\n        id,\n        name: skill.name,\n        description: skill.description,\n        content: skill.content,\n        files: (skill.files ?? [])\n          .map(file => ({\n            path: normalizeSkillFilePath({\n              skillName: skill.name,","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/vercel/ai/blob/69428b1f8b037e4d118fb4853428d5c4e620493c/packages/harness-cline/src/cline-skills.ts#L81-L117","documentation":"projectClineSkills builds the projected skill list for the Cline harness and requires each skill directory name to be unique. When two skills resolve to the same name it throws to prevent ambiguous skill references. This guards the integrity of the skill catalog exposed to the model.","triggerScenarios":"Calling projectedSkills/projectClineSkills with a skills input where two skill entries have the same `name` property (e.g. two directories or declared skills both named 'deploy').","commonSituations":"Mounting multiple skill directories that contain same-named skill folders; merging skill sources (user + repo skills) without deduplication; copying a skill folder under two parents that both get scanned.","solutions":["Rename one of the conflicting skills so every skill name is unique.","Deduplicate the skill list before passing it to the harness (filter by name).","If skills come from overlapping directories, exclude the duplicated source directory."],"exampleFix":"// before\nconst skills = [...userSkills, ...repoSkills]; // both contain 'review-pr'\n// after\nconst seen = new Set();\nconst skills = [...userSkills, ...repoSkills].filter(s =>\n  !seen.has(s.name) && seen.add(s.name)\n);","handlingStrategy":"validation","validationCode":"const names = new Set();\nfor (const s of skills) {\n  if (names.has(s.name)) throw new Error(`duplicate skill name: ${s.name}`);\n  names.add(s.name);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await projectedSkills(input);\n} catch (e) {\n  if (/Duplicate Cline skill name/.test(String(e?.message))) {\n    // dedupe/rename skills and retry\n  } else throw e;\n}","preventionTips":["Keep one canonical skill directory per name","Deduplicate merged skill sources by name before registering","Log skill names at startup to spot collisions early"],"tags":["harness-cline","skills","configuration","duplicate-name"],"backgroundTag":"duplicate-resource-name","analyzedSha":"69428b1f8b037e4d118fb4853428d5c4e620493c","analyzedAt":"2026-08-30T12:32:21.016Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}