{"record":{"id":"1814809002b22a41","repo":"mastra-ai/mastra","slug":"workspaceskills-cannot-resolve-skill-winner-n","errorCode":null,"errorMessage":"[WorkspaceSkills] Cannot resolve skill \"${winner.name}\": multiple ${winner.source.type} skills found at ${paths}. Rename one or move it to a different source type.","messagePattern":"\\[WorkspaceSkills\\] Cannot resolve skill \"(.+?)\": multiple (.+?) skills found at (.+?)\\. Rename one or move it to a different source type\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/workspace/skills/workspace-skills.ts","lineNumber":359,"sourceCode":"\n    const SOURCE_PRIORITY: Record<string, number> = { local: 0, managed: 1, external: 2 };\n    const sorted = [...deduped].sort((a, b) => {\n      const aPri = SOURCE_PRIORITY[a.source.type] ?? 99;\n      const bPri = SOURCE_PRIORITY[b.source.type] ?? 99;\n      if (aPri !== bPri) return aPri - bPri;\n      return a.path.localeCompare(b.path);\n    });\n\n    const winner = sorted[0]!;\n    const runnerUp = sorted[1]!;\n\n    // Error if source-type priority can't break the tie\n    if (winner.source.type === runnerUp.source.type) {\n      const paths = sorted\n        .filter(s => s.source.type === winner.source.type)\n        .map(s => `\"${s.path}\"`)\n        .join(', ');\n      throw new Error(\n        `[WorkspaceSkills] Cannot resolve skill \"${winner.name}\": multiple ${winner.source.type} skills found at ${paths}. ` +\n          `Rename one or move it to a different source type.`,\n      );\n    }\n\n    console.warn(\n      `[WorkspaceSkills] Multiple skills named \"${winner.name}\" found. ` +\n        `Using \"${winner.path}\" (source: ${winner.source.type}). ` +\n        `Other candidates: ${sorted\n          .slice(1)\n          .map(s => `\"${s.path}\" (${s.source.type})`)\n          .join(', ')}`,\n    );\n\n    return winner;\n  }\n\n  async refresh(): Promise<void> {","sourceCodeStart":341,"sourceCodeEnd":377,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/workspace/skills/workspace-skills.ts#L341-L377","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Rename one of the conflicting skills (its directory and/or the name field in its SKILL.md frontmatter) so names are unique.","Move one duplicate to a different source type (e.g. from local to repo scope) so priority can break the tie.","Delete the stale duplicate if it's an leftover copy.","List available skills first and reference the intended one unambiguously."],"exampleFix":"// before\n// skills/brand-guidelines/SKILL.md  -> name: brand-guidelines\n// backup/brand-guidelines/SKILL.md  -> name: brand-guidelines (duplicate)\n// after\n// backup/brand-guidelines/SKILL.md -> name: brand-guidelines-legacy","handlingStrategy":"validation","validationCode":"const matches = await workspaceSkills.list().then(all => all.filter(s => s.name === 'brand-guidelines'));\nconst sameType = new Set(matches.map(m => m.source.type));\nif (matches.length > 1 && sameType.size === matches.length && matches.length > 1) {\n  throw new Error(`Duplicate skill name 'brand-guidelines' in the same source type — rename one before resolving by name.`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  const skill = await workspaceSkills.skill('brand-guidelines');\n} catch (err) {\n  if (err instanceof Error && err.message.includes('Cannot resolve skill')) {\n    // prompt user to disambiguate or fall back to a default skill\n  } else throw err;\n}","preventionTips":["Enforce unique skill names within each source type via lint/CI checks on SKILL.md frontmatter.","Update the frontmatter name whenever you copy or fork a skill directory.","Prefer explicit path-based access when duplicates may temporarily exist.","Read the error's path list to find exactly which duplicates to rename."],"tags":["skills","naming-conflict","resolution","configuration"],"backgroundTag":"duplicate-skill-name","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}