vercel/ai · error · Error

Invalid skill file path for ${skillName}: ${filePath}

Error message

Invalid skill file path for ${skillName}: ${filePath}

What it means

Thrown by normalizeSkillFilePath in the harness package when a skill file path fails safety validation after normalization. Paths that escape the skill directory ('..' traversal segments), are empty, are '.', or are absolute when a relative path is required are rejected. This prevents writing skill files outside the intended skill folder (path traversal).

Source

Thrown at packages/harness/src/utils/write-skills.ts:511

  skillName?: string;
  filePath: string;
  mode: SkillFilePathMode;
  message?: (input: { skillName: string; filePath: string }) => string;
}): string {
  const normalized =
    mode === 'strip-leading-slashes'
      ? filePath.replace(/^\/+/, '')
      : path.posix.normalize(filePath);
  const invalid =
    normalized === '' ||
    (mode === 'relative' && normalized === '.') ||
    normalized.startsWith('../') ||
    normalized.includes('/../') ||
    normalized.endsWith('/..') ||
    (mode === 'relative' && path.posix.isAbsolute(normalized));

  if (invalid) {
    throw new Error(
      message?.({ skillName: skillName ?? '', filePath }) ??
        `Invalid skill file path for ${skillName}: ${filePath}`,
    );
  }
  return normalized;
}

function renderSkillFile({
  skill,
  trailingNewline,
}: {
  skill: HarnessV1Skill;
  trailingNewline: boolean;
}): string {
  const content = `---\nname: ${skill.name}\ndescription: ${skill.description}\n---\n\n${skill.content}`;
  return trailingNewline ? `${content}\n` : content;
}

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Remove any '..' segments, leading slashes, and empty/ '.' paths from the skill's file path so it is a plain relative path like 'reference.md' or 'scripts/run.sh'.
  2. If the path comes from user input, sanitize it first (normalize, reject absolute and traversal segments) before passing it to the skills API.
  3. Read the thrown message — it names the offending skillName and filePath — and correct that specific entry in the manifest.

Example fix

// before
skills: [{ name: 'my-skill', files: [{ path: '../../etc/hosts', content: '...' }] }]
// after
skills: [{ name: 'my-skill', files: [{ path: 'etc-notes.md', content: '...' }] }]
Defensive patterns

Strategy: validation

Validate before calling

function isSafeSkillFilePath(p) {
  const normalized = p.replace(/^\/+/, '');
  return (
    normalized !== '' && normalized !== '.' &&
    !normalized.startsWith('../') && !normalized.includes('/../') &&
    !normalized.endsWith('/..')
  );
}
if (!isSafeSkillFilePath(skillFile.path)) throw new Error(`Refusing unsafe skill path: ${skillFile.path}`);

Try / catch

try {
  await projectSkills({ skills });
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Invalid skill file path')) {
    console.error(`Fix skill manifest path: ${e.message}`);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling projectSkill (or write-skills APIs) with a skill whose file path: contains '../' segments, resolves to '' or '.', starts with '/', or equals/ends with '..'. Also triggered when mode is 'relative' and the normalized path is absolute.

Common situations: Programmatically generated skill manifests with user-supplied paths; migrating skills from another tool that used absolute paths; accidental '..' in a path template; empty file path fields in skill YAML frontmatter.

Related errors


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