mastra-ai/mastra · error
Sync function "${name}" already registered
Error message
Sync function "${name}" already registered What it means
MastraIntegration.registerWorkflow stores workflows in a plain name-keyed map and treats duplicate registration as a programming error. If a workflow with the same name already exists in this.#workflows, it throws instead of overwriting, preventing accidental replacement of a registered workflow.
Source
Thrown at packages/core/src/integration/integration.ts:18
import type { ToolAction } from '../tools';
import type { Workflow } from '../workflows';
export class Integration<ToolsParams = void, ApiClient = void> {
name: string = 'Integration';
private workflows: Record<string, Workflow>;
constructor() {
this.workflows = {};
}
/**
* Workflows
*/
registerWorkflow(name: string, fn: Workflow) {
if (this.workflows[name]) {
throw new Error(`Sync function "${name}" already registered`);
}
this.workflows[name] = fn;
}
public listWorkflows({ serialized }: { serialized?: boolean }): Record<string, Workflow> {
if (serialized) {
return Object.entries(this.workflows).reduce((acc, [k, v]) => {
return {
...acc,
[k]: {
name: v.name,
},
};
}, {});
}
return this.workflows;
}
View on GitHub (pinned to 75dd419e61)
Solutions
- Register each workflow only once — move registration to module top-level or a run-once init function
- Give duplicate registrations unique names, or check existing names via listWorkflows() first
- Use this.workflows[name] ?? this.registerWorkflow(...) semantics yourself, or add an idempotency guard in your registration code
- If caused by HMR, clear registrations on module dispose or use a guard keyed on module state
Example fix
// before
integration.registerWorkflow('deploy', deployWorkflow);
integration.registerWorkflow('deploy', deployWorkflowV2); // throws
// after
if (!Object.keys(integration.listWorkflows({})).includes('deploy')) {
integration.registerWorkflow('deploy', deployWorkflow);
} Defensive patterns
Strategy: validation
Validate before calling
if (Object.keys(integration.listWorkflows({})).includes(name)) {
throw new Error(`Workflow "${name}" is already registered`);
} Type guard
function isWorkflowRegistered(integration, name) {
return Object.prototype.hasOwnProperty.call(integration.listWorkflows({}), name);
} Try / catch
try {
integration.registerWorkflow(name, workflow);
} catch (e) {
if (e.message.includes('already registered')) {
// idempotent registration — safe to ignore or log
} else {
throw e;
}
} Prevention
- Keep workflow registration in a single module/init function
- Use unique, namespaced workflow names
- Add run-once guards for HMR/dev-server double execution
- Before registering, check listWorkflows() for name collisions
When it happens
Trigger: Calling integration.registerWorkflow(name, fn) twice with the same name — e.g. re-registering during hot module reload (HMR), double module import, or registering the same workflow instance under a conflicting key.
Common situations: Dev-server hot reload re-running registration code; two files both registering a workflow named 'deploy'; a factory function invoked more than once; copy-pasted registration blocks with the same name.
Related errors
- Workflow ${workflowId} not found
- MastraFactory: duplicate integration id '${integration.id}'
- MastraFactory: integration tool '${name}' from '${ownerId}'
- Dynamic workflow references agent "${entry.agentId}" which i
- Dynamic workflow references tool "${entry.toolId}" which is
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/8b4c83d26cf78725.
Report an issue: GitHub.