mastra-ai/mastra · error

Duplicate workspace tool name "${exposedName}": tool "${name

Error message

Duplicate workspace tool name "${exposedName}": tool "${name}" conflicts with an already-registered tool. Check your tools config for duplicate "name" values.

What it means

Workspace tool registration keys tools by their exposed name (`config.name ?? defaultName`). If two tool configs resolve to the same exposed name, `addTool` throws a duplicate-name Error so registration fails fast rather than silently overwriting a tool. The error names both the internal tool and the colliding exposed name.

Source

Thrown at packages/core/src/workspace/tools/tools.ts:466

              workspace: ctx?.workspace ?? workspace,
            },
            true,
          ),
      };
    } else {
      wrapped = { ...tool, requireApproval: config.requireApproval };
    }

    if (opts?.readTrackerMode) {
      wrapped = wrapWithReadTracker(wrapped, workspace, readTracker, config, opts.readTrackerMode);
    } else {
      wrapped = wrapTool(wrapped, workspace, opts?.targets ?? {});
    }

    // Use custom name if provided, otherwise use the default constant name
    const exposedName = config.name ?? name;
    if (tools[exposedName]) {
      throw new Error(
        `Duplicate workspace tool name "${exposedName}": tool "${name}" conflicts with an already-registered tool. ` +
          `Check your tools config for duplicate "name" values.`,
      );
    }
    // When the tool is renamed, update its id to match so fallback-by-id
    // resolution (in tool-call-step, llm-execution-step, etc.) won't allow
    // the model to call the tool using the old default name.
    if (exposedName !== name && 'id' in wrapped) {
      wrapped = { ...wrapped, id: exposedName };
    }

    if (config.hooks) {
      wrapped = wrapWithToolHooks(wrapped, config.hooks, exposedName, name);
    }

    // Write lock is outermost — serializes the entire enriched execute pipeline
    if (opts?.useWriteLock) {
      wrapped = wrapWithWriteLock(wrapped, writeLock);

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Give each conflicting tool config a unique `name`
  2. Remove the duplicate config entry if it was added by mistake
  3. If two instances of the same built-in tool are needed with different settings, expose them under distinct names

Example fix

// before
{ tool: 'read-file', name: 'read' },
{ tool: 'read-many-files', name: 'read' } // duplicate

// after
{ tool: 'read-file', name: 'read' },
{ tool: 'read-many-files', name: 'read-many' }
Defensive patterns

Strategy: validation

Validate before calling

const names = toolConfigs.map(c => c.name ?? defaultNameFor(c.tool));
const dupes = names.filter((n, i) => names.indexOf(n) !== i);
if (dupes.length) throw new Error(`Duplicate workspace tool names: ${[...new Set(dupes)].join(', ')}`);

Try / catch

try {
  const tools = createWorkspaceToolConfigs(configs);
} catch (err) {
  if (err instanceof Error && err.message.startsWith('Duplicate workspace tool name')) {
    console.error(err.message); // fix config names
    throw err;
  }
  throw err;
}

Prevention

When it happens

Trigger: Providing the same custom `name` for two different tool configs, or enabling the same built-in workspace tool twice (e.g. two read-file entries) so both map to one constant default name.

Common situations: Copy-pasting a tool config entry and forgetting to change `name`; spreading arrays of tool configs that both contain a renamed tool with the same name; dynamic config generation producing duplicate names.

Related errors


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