mastra-ai/mastra · error

[WorkspaceSkills] Cannot resolve skill "${winner.name}": mul

Error message

[WorkspaceSkills] Cannot resolve skill "${winner.name}": multiple ${winner.source.type} skills found at ${paths}. Rename one or move it to a different source type.

What it means

WorkspaceSkills resolves skills by name across multiple sources (local, repo, published, etc.) using source-type priority as a tiebreaker. When the top two candidates share the same source type, priority cannot disambiguate, so #tieBreak throws instead of silently picking one. The message lists every same-type path so the developer can rename or relocate the duplicates.

Source

Thrown at packages/core/src/workspace/skills/workspace-skills.ts:359

    const SOURCE_PRIORITY: Record<string, number> = { local: 0, managed: 1, external: 2 };
    const sorted = [...deduped].sort((a, b) => {
      const aPri = SOURCE_PRIORITY[a.source.type] ?? 99;
      const bPri = SOURCE_PRIORITY[b.source.type] ?? 99;
      if (aPri !== bPri) return aPri - bPri;
      return a.path.localeCompare(b.path);
    });

    const winner = sorted[0]!;
    const runnerUp = sorted[1]!;

    // Error if source-type priority can't break the tie
    if (winner.source.type === runnerUp.source.type) {
      const paths = sorted
        .filter(s => s.source.type === winner.source.type)
        .map(s => `"${s.path}"`)
        .join(', ');
      throw new Error(
        `[WorkspaceSkills] Cannot resolve skill "${winner.name}": multiple ${winner.source.type} skills found at ${paths}. ` +
          `Rename one or move it to a different source type.`,
      );
    }

    console.warn(
      `[WorkspaceSkills] Multiple skills named "${winner.name}" found. ` +
        `Using "${winner.path}" (source: ${winner.source.type}). ` +
        `Other candidates: ${sorted
          .slice(1)
          .map(s => `"${s.path}" (${s.source.type})`)
          .join(', ')}`,
    );

    return winner;
  }

  async refresh(): Promise<void> {

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Rename one of the conflicting skills (its directory and/or the name field in its SKILL.md frontmatter) so names are unique.
  2. Move one duplicate to a different source type (e.g. from local to repo scope) so priority can break the tie.
  3. Delete the stale duplicate if it's an leftover copy.
  4. List available skills first and reference the intended one unambiguously.

Example fix

// before
// skills/brand-guidelines/SKILL.md  -> name: brand-guidelines
// backup/brand-guidelines/SKILL.md  -> name: brand-guidelines (duplicate)
// after
// backup/brand-guidelines/SKILL.md -> name: brand-guidelines-legacy
Defensive patterns

Strategy: validation

Validate before calling

const matches = await workspaceSkills.list().then(all => all.filter(s => s.name === 'brand-guidelines'));
const sameType = new Set(matches.map(m => m.source.type));
if (matches.length > 1 && sameType.size === matches.length && matches.length > 1) {
  throw new Error(`Duplicate skill name 'brand-guidelines' in the same source type — rename one before resolving by name.`);
}

Try / catch

try {
  const skill = await workspaceSkills.skill('brand-guidelines');
} catch (err) {
  if (err instanceof Error && err.message.includes('Cannot resolve skill')) {
    // prompt user to disambiguate or fall back to a default skill
  } else throw err;
}

Prevention

When it happens

Trigger: Requesting a skill by name when two or more skills with that exact name exist in the same source type — e.g. two 'brand-guidelines' directories in the same local skills folder, or duplicate names across repos mapped to the same source type.

Common situations: Cloning/renaming a skill folder and forgetting to update its name in SKILL.md frontmatter; merging branches that each added a skill with the same name; syncing skills between projects without renaming; case-only differences deduplicated into the same name.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/1814809002b22a41. Report an issue: GitHub.