mastra-ai/mastra · error
MastraFactory: duplicate integration id '${integration.id}'
Error message
MastraFactory: duplicate integration id '${integration.id}' in 'integrations'. What it means
During prepare(), the factory validates that every integration id in config.integrations is unique before building the registrations. Duplicate ids would cause one integration instance to silently shadow the other in lookups and tool registries, so the factory fails loud with the offending id instead. The check runs up front, before rules validation and any side effects.
Source
Thrown at mastracode/factory/src/factory.ts:355
// Explicit integrations win. Platform credentials fill only missing GitHub
// and Linear slots so callers can override either provider independently.
const integrations = [...(this.#config.integrations ?? [])];
if (hasPlatformCredentials()) {
if (!integrations.some(integration => integration.id === 'github')) {
integrations.push(new PlatformGithubIntegration({ slug: this.#config.platform?.githubAppSlug }));
}
if (!integrations.some(integration => integration.id === 'linear')) {
integrations.push(new PlatformLinearIntegration());
}
}
// Validate ids up front so a copy-paste duplicate fails loud instead of one
// instance silently shadowing the other.
const integrationIds = new Set<string>();
for (const integration of integrations) {
if (integrationIds.has(integration.id)) {
throw new Error(`MastraFactory: duplicate integration id '${integration.id}' in 'integrations'.`);
}
integrationIds.add(integration.id);
}
const rules = this.#config.rules ?? builtInFactoryRules();
assertFactoryRules(rules);
// FactoryStorage owns every app-table domain and initializes them through
// the same lifecycle as the backend connection.
const intakeStorage = storage.registerDomain(new IntakeStorage());
const auditStorage = storage.registerDomain(new AuditStorage());
const workItemsStorage = storage.registerDomain(new WorkItemsStorage());
const modelCredentialsStorage = storage.registerDomain(new ModelCredentialsStorage(secretEncryption));
const modelPacksStorage = storage.registerDomain(new ModelPacksStorage());
const memorySettingsStorage = storage.registerDomain(new MemorySettingsStorage());
const customProvidersStorage = storage.registerDomain(new CustomProvidersStorage(secretEncryption));
const queueHealthStorage = storage.registerDomain(new QueueHealthStorage());
// Generic integration storage (connections/subscriptions/settings) — the
// default persistence surface for integrations without a bespoke domain.View on GitHub (pinned to 75dd419e61)
Solutions
- Deduplicate the integrations array before constructing the factory (e.g. filter by id or use a Map keyed by id).
- Give each integration instance a unique id when registering it.
- Check for accidental double-spreading of the integrations array in the config.
- Log or assert the list of ids in your config builder to catch duplicates early in tests.
Example fix
// before integrations: [githubIntegration, githubIntegration] // after integrations: [githubIntegration, slackIntegration] // unique ids
Defensive patterns
Strategy: validation
Validate before calling
function assertUniqueIntegrationIds(integrations) {
const ids = integrations.map(i => i.id);
const dupes = ids.filter((id, i) => ids.indexOf(id) !== i);
if (dupes.length) throw new Error(`Duplicate integration ids: ${dupes.join(', ')}`);
}
assertUniqueIntegrationIds(factoryConfig.integrations ?? []); Type guard
function hasUniqueIds(integrations) {
return Array.isArray(integrations) && new Set(integrations.map(i => i.id)).size === integrations.length;
} Try / catch
try {
const factory = new MastraFactory(config);
await factory.prepare();
} catch (err) {
if (err.message.includes('duplicate integration id')) {
const id = err.message.match(/'([^']+)'/)?.[1];
throw new Error(`Fix config: integration '${id}' registered more than once`, { cause: err });
}
throw err;
} Prevention
- Build the integrations array from a single source of truth (a registry module), not inline literals
- Deduplicate by id when merging integration lists from multiple sources
- Add a test asserting hasUniqueIds on the production config
- Avoid copy-pasting integration registrations without changing ids
When it happens
Trigger: Passing two integration instances with the same integration.id in the integrations array of the factory config — typically from a copy-pasted registration or pushing the same integration object/array element twice (e.g. [...integrations, githubIntegration, githubIntegration]).
Common situations: Copy-pasting an integration registration and forgetting to change its id; accidentally spreading an integrations array twice; constructing two instances of the same integration class that share a static default id.
Related errors
- Google RBAC roleMapping is required.
- Cookie password must be at least 32 characters. Set OKTA_COO
- heartbeatMs must be a finite number no greater than ${MAX_TI
- Expected a PEM-encoded public key or certificate string for
- terminationGraceMs must be greater than zero.
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/490c5fff88335026.
Report an issue: GitHub.