{"record":{"id":"e772f5c8fbfdc3ad","repo":"mastra-ai/mastra","slug":"agent-fs-routing-subagent-name-collision","errorCode":"AGENT_FS_ROUTING_SUBAGENT_NAME_COLLISION","errorMessage":"Agent \"${name}\": duplicate subagent \"${childId}\" under agents/${name}/subagents/.","messagePattern":"Agent \"(.+?)\": duplicate subagent \"(.+?)\" under agents/(.+?)/subagents/\\.","errorType":"error_code","errorClass":"MastraError","httpStatus":null,"severity":"error","filePath":"packages/core/src/agent/fs-routing/index.ts","lineNumber":637,"sourceCode":"  if (typeof configAgents === 'function') {\n    if (fsSubAgents.length > 0) {\n      onWarn(\n        `Agent \"${name}\": config.agents is a function, so discovered subagents under agents/${name}/subagents/ are ignored.`,\n      );\n    }\n    return configAgents;\n  }\n\n  const fromConfig = (configAgents ?? {}) as Record<string, Agent>;\n  const configKeys = new Set(Object.keys(fromConfig));\n  const toolKeys = new Set(Object.keys(mergedTools ?? {}));\n\n  const fromFs: Record<string, Agent> = {};\n  for (const childEntry of fsSubAgents) {\n    const childId = childEntry.name;\n\n    if (childId in fromFs) {\n      throw new MastraError({\n        id: 'AGENT_FS_ROUTING_SUBAGENT_NAME_COLLISION',\n        domain: ErrorDomain.AGENT,\n        category: ErrorCategory.USER,\n        details: { agentName: name, subagentName: childId },\n        text: `Agent \"${name}\": duplicate subagent \"${childId}\" under agents/${name}/subagents/.`,\n      });\n    }\n\n    if (toolKeys.has(childId)) {\n      throw new MastraError({\n        id: 'AGENT_FS_ROUTING_SUBAGENT_NAME_COLLISION',\n        domain: ErrorDomain.AGENT,\n        category: ErrorCategory.USER,\n        details: { agentName: name, subagentName: childId },\n        text: `Agent \"${name}\": subagent \"${childId}\" collides with a tool of the same name. Rename agents/${name}/subagents/${childId}/ or the tool.`,\n      });\n    }\n","sourceCodeStart":619,"sourceCodeEnd":655,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/agent/fs-routing/index.ts#L619-L655","documentation":"During filesystem-based agent assembly, mergeSubAgents collects subagents from agents/<name>/subagents/ and builds a keyed record. If two subagent directories resolve to the same agent id (childEntry.name), the second insertion is detected as a duplicate and this error is thrown. Duplicate ids are ambiguous for routing/selection, so the library fails fast instead of silently shadowing one subagent.","triggerScenarios":"Two directories under agents/<name>/subagents/ whose config.ts declare the same agent name/id; a subagent whose constructed Agent .name matches another entry; case-insensitive filesystems where 'Research/' and 'research/' directories coexist and both normalize to the same id.","commonSituations":"Copying an existing subagent directory to tweak it but forgetting to change the `name` in the new config.ts; symlinking a shared subagent under two paths; renaming a directory on disk without updating the agent name inside config.ts.","solutions":["Open each agents/<name>/subagents/<child>/config.ts and give every subagent a unique `name` (the collision id is in the error details: subagentName).","Rename or remove one of the duplicate directories if it is an accidental copy.","Check for symlinks or duplicate directory entries (including case-only differences) that make the same subagent appear twice."],"exampleFix":"// before (agents/main/subagents/researcher-copy/config.ts)\nexport const config = { name: 'researcher', /* ... */ };\n\n// after\nexport const config = { name: 'researcher-copy', /* ... */ };","handlingStrategy":"validation","validationCode":"import { readdirSync, readFileSync } from 'node:fs';\nconst dirs = readdirSync('./agents/main/subagents', { withFileTypes: true }).filter(d => d.isDirectory());\nconst names = dirs.map(d => {\n  const cfg = readFileSync(`./agents/main/subagents/${d.name}/config.ts`, 'utf8');\n  return /name:\\s*['\"]([^'\"]+)['\"]/.exec(cfg)?.[1];\n});\nconst dupes = names.filter((n, i) => n && names.indexOf(n) !== i);\nif (dupes.length) throw new Error(`Duplicate subagent names: ${dupes}`);","typeGuard":null,"tryCatchPattern":"try {\n  buildAgentFromFs('main');\n} catch (e) {\n  if (e instanceof MastraError && e.id === 'AGENT_FS_ROUTING_SUBAGENT_NAME_COLLISION') {\n    console.error('Subagent name collision:', e.detail?.subagentName);\n  } else throw e;\n}","preventionTips":["When copying a subagent directory, immediately change the `name` in the copied config.ts","Keep directory names and config `name` identical to avoid confusion","CI lint: assert subagent names across all agents are unique","Avoid case-only directory name differences"],"tags":["agent","subagents","naming-collision","filesystem-routing"],"backgroundTag":"duplicate-identifier","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}