vercel/ai · error · Error

Invalid Cline skill name: ${skill.name}

Error message

Invalid Cline skill name: ${skill.name}

What it means

projectClineSkills validates each skill's name against CLINE_SKILL_NAME_PATTERN and additionally rejects '.' and '..'. Names failing the pattern (which disallow path-hostile or malformed identifiers) throw this plain Error before any duplicate check. Cline maps skill names to directories, so unsafe names would escape or break the skills layout.

Source

Thrown at packages/harness-cline/src/cline-skills.ts:96

  return { signature, tool };
}

function projectClineSkills({
  skills,
}: {
  skills: ReadonlyArray<HarnessV1Skill>;
}): ReadonlyArray<ProjectedClineSkill> {
  const names = new Set<string>();
  const ids = new Set<string>();
  return skills
    .map(skill => {
      if (
        !CLINE_SKILL_NAME_PATTERN.test(skill.name) ||
        skill.name === '.' ||
        skill.name === '..'
      ) {
        throw new Error(`Invalid Cline skill name: ${skill.name}`);
      }
      if (names.has(skill.name)) {
        throw new Error(`Duplicate Cline skill name: ${skill.name}`);
      }
      names.add(skill.name);

      const id = normalizeSkillToken(skill.name);
      if (ids.has(id)) {
        throw new Error(`Duplicate Cline skill identifier: ${id}`);
      }
      ids.add(id);

      return {
        id,
        name: skill.name,
        description: skill.description,
        content: skill.content,
        files: (skill.files ?? [])

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Rename the offending skill so its name matches CLINE_SKILL_NAME_PATTERN (kebab-case-ish, no separators, not '.' or '..').
  2. Sanitize names at load time: derive the name from the filename, trim, replace invalid characters with '-', and skip entries like '.'/'..'.
  3. Add a preflight filter in your skill loader that mirrors the harness regex so invalid skills are rejected early with a clearer message.

Example fix

// before
prompt({ skills: [{ name: '../hostile', ... }] });
// after
const safeName = rawName.replace(/[^a-zA-Z0-9_-]/g, '-').replace(/^-+|-+$/g, '');
prompt({ skills: [{ name: safeName || 'skill', ... }] });
Defensive patterns

Strategy: validation

Validate before calling

const CLINE_SKILL_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]*$/; // mirror harness pattern
function assertValidSkillName(name: string) {
  if (!CLINE_SKILL_NAME_PATTERN.test(name) || name === '.' || name === '..') {
    throw new Error(`Invalid skill name: ${name}`);
  }
}
skills.forEach(s => assertValidSkillName(s.name));

Try / catch

try {
  await session.prompt({ text, skills });
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Invalid Cline skill name')) {
    const bad = e.message.split(': ')[1];
    skills = skills.filter(s => s.name !== bad);
    await session.prompt({ text, skills });
  } else throw e;
}

Prevention

When it happens

Trigger: Passing a skill in turnOpts.skills whose name is empty, contains characters outside the allowed pattern (e.g. spaces, slashes, 'my skill/', '../escape'), or is exactly '.' or '..'.

Common situations: Generating skill names from user input or file paths without normalization; loading skills from a directory and using raw folder names including spaces or unicode; hand-written skill definitions with typos or separators in the name.

Related errors


AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/dffc2a5b8bfda6cd. Report an issue: GitHub.