mastra-ai/mastra · error
MastraFactory: integration tool '${name}' from '${ownerId}'
Error message
MastraFactory: integration tool '${name}' from '${ownerId}' conflicts with '${owner}'. What it means
Each integration contributes named tools; mergeTools tracks the owner of every tool name in a Map and throws when a second integration tries to register a tool name already claimed by another. Without this check the later integration would silently overwrite the earlier one's tool, changing agent behavior. The error names the tool, the conflicting integration id, and the original owner.
Source
Thrown at mastracode/factory/src/factory.ts:678
factoryOrgUnresolved: true,
projectPath: '',
projectName: '',
gitBranch: '',
},
storage: storage.getMastraStorage(),
...(mastraStorageBackend ? { storageBackend: mastraStorageBackend } : {}),
...(factoryProcessor ? { inputProcessors: [factoryProcessor] } : {}),
...(vector ? { vector } : {}),
...(toolIntegrations.length > 0 || (workItemsStorage && transitionService)
? {
extraTools: async ({ requestContext }: { requestContext: RequestContext }) => {
const tools: IntegrationTools = {};
const toolOwners = new Map<string, string>();
const mergeTools = (ownerId: string, contributed: IntegrationTools) => {
for (const [name, tool] of Object.entries(contributed)) {
const owner = toolOwners.get(name);
if (owner) {
throw new Error(
`MastraFactory: integration tool '${name}' from '${ownerId}' conflicts with '${owner}'.`,
);
}
toolOwners.set(name, ownerId);
tools[name] = tool;
}
};
if (workItemsStorage && transitionService) {
mergeTools(
'factory',
await createFactoryTransitionTools({
requestContext,
storage: workItemsStorage,
transitionService,
// Heals crash-resumed sessions: recovered addresses re-seed
// projectRepositoryId/baseRef from the source session record.
// Only offered while the source-control domain is ready — a
// throwing lookup would abort recovery's catch block and alsoView on GitHub (pinned to 75dd419e61)
Solutions
- Rename the tool in your custom integration so its exported name is unique (e.g. prefix with the integration id: githubCreateIssue).
- Remove one of the two integrations if they are redundant.
- Check the error's owner names to identify which two integrations collide and coordinate the naming.
- Namespace all tool names by their integration id as a team convention to prevent future collisions.
Example fix
// before
// custom-integration.ts
export const createIssue = createTool({ ... }); // clashes with github's createIssue
// after
export const trackerCreateIssue = createTool({ ... }); // unique name Defensive patterns
Strategy: validation
Validate before calling
function assertUniqueToolNames(integrations) {
const seen = new Map();
for (const integration of integrations) {
for (const toolName of Object.keys(integration.tools ?? {})) {
if (seen.has(toolName)) throw new Error(`Tool '${toolName}' provided by both '${seen.get(toolName)}' and '${integration.id}'`);
seen.set(toolName, integration.id);
}
}
}
assertUniqueToolNames(factoryConfig.integrations ?? []); Type guard
function toolsAreNamespaced(integrations) {
return integrations.every(i =>
Object.keys(i.tools ?? {}).every(name => name.startsWith(i.id + '_'))
);
} Try / catch
try {
await factory.prepare();
} catch (err) {
const m = err.message.match(/integration tool '(\w+)' from '(\S+)' conflicts with '(\S+)'/);
if (m) throw new Error(`Rename tool '${m[1]}' in '${m[2]}' (already owned by '${m[3]}')`, { cause: err });
throw err;
} Prevention
- Prefix every tool name with its integration id (e.g. githubCreateIssue)
- Keep a shared registry of reserved tool names
- Review new integrations for generic names like 'search' or 'create'
- Add a config test that pre-merges tool names and asserts uniqueness
When it happens
Trigger: Two integrations in config.integrations both register a tool with the same exported name — e.g. both a custom integration and a built-in export a tool called 'createIssue', so the second merge call hits an existing owner in toolOwners.
Common situations: Building a custom integration that reuses a generic tool name like 'search' or 'createTicket' that a built-in integration already uses; enabling two integrations that both wrap the same upstream API; renaming an integration id without renaming its tool names.
Related errors
- MastraFactory: duplicate integration id '${integration.id}'
- Sync function "${name}" already registered
- Method not implemented.
- Agent "${agentId}" is already connected to Slack. Disconnect
- @mastra/livekit: the agent requested tool approval or suspen
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/97e283e8d83029db.
Report an issue: GitHub.