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

  1. Register each workflow only once — move registration to module top-level or a run-once init function
  2. Give duplicate registrations unique names, or check existing names via listWorkflows() first
  3. Use this.workflows[name] ?? this.registerWorkflow(...) semantics yourself, or add an idempotency guard in your registration code
  4. 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

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


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/8b4c83d26cf78725. Report an issue: GitHub.