mastra-ai/mastra · error · Error

Tool '${entry.toolId}' not found for workflow step '${entry.

Error message

Tool '${entry.toolId}' not found for workflow step '${entry.id}'. Pass the tool instance directly.

What it means

A workflow step references a tool by toolId, but neither an instance on the step entry (entry.tool) nor a tool registered under that id on the Mastra instance could be resolved. runToolEntry throws this Error before executing the step.

Source

Thrown at packages/core/src/workflows/entry-executors/run-tool-entry.ts:16

import type { Mastra } from '../../mastra';
import { resolveObservabilityContext } from '../../observability';
import type { ToolStepEntry } from '../types';
import { resolveEntryActor } from './actor';
import type { EntryExecuteContext } from './types';

/**
 * Runs a declarative `tool` entry: resolves the tool (inline handle, else the
 * Mastra registry) and executes it with the step context mapped into the tool
 * execution context.
 */
export async function runToolEntry(entry: ToolStepEntry, ctx: EntryExecuteContext, mastra?: Mastra): Promise<unknown> {
  const registry = mastra ?? (ctx?.mastra as Mastra | undefined);
  const tool = entry.tool ?? registry?.getTool(entry.toolId);
  if (!tool) {
    throw new Error(
      `Tool '${entry.toolId}' not found for workflow step '${entry.id}'. Pass the tool instance directly.`,
    );
  }

  const {
    inputData,
    mastra: ctxMastra,
    requestContext,
    suspend,
    resumeData,
    runId,
    workflowId,
    state,
    setState,
    abortSignal,
    actor,
    ...rest
  } = ctx;

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Register the tool on the Mastra instance: new Mastra({ tools: { myToolId: myTool } }).
  2. Or pass the tool instance directly on the step entry: { id: 'step', tool: myTool } (note the message says instance is required here, unlike agents).
  3. Verify toolId matches the registration key exactly.
  4. Ensure the Mastra instance is reachable by the engine (mastra param or ctx.mastra).

Example fix

// before
steps: [{ id: 'fetch', toolId: 'fetchWeather' }] // never registered
// after
steps: [{ id: 'fetch', tool: createTool({ id: 'fetchWeather', ... }) }]
// or: new Mastra({ tools: { fetchWeather: weatherTool } })
Defensive patterns

Strategy: validation

Validate before calling

const tool = entry.tool ?? mastra?.getTool(entry.toolId);
if (!tool) throw new Error(`Step '${entry.id}' references unregistered tool '${entry.toolId}'`);

Type guard

function hasTool(entry: { tool?: unknown; toolId: string }, mastra?: Mastra): boolean {
  return !!entry.tool || !!mastra?.getTool(entry.toolId);
}

Try / catch

try { await runToolEntry(entry, ctx, mastra); } catch (e) { if (e instanceof Error && e.message.includes("Tool '") && e.message.includes("not found")) { attachToolInstance(entry); } else throw e; }

Prevention

When it happens

Trigger: Executing a (dynamic) workflow whose ToolStepEntry has toolId set but entry.tool undefined, while registry.getTool(entry.toolId) returns undefined — the tool was never registered on the Mastra instance or the id is wrong.

Common situations: Dynamic/codegen workflows referencing tool ids that were not registered; tools created locally but not passed to Mastra; typos or renamed tool ids; running the engine without the Mastra instance in scope.

Related errors


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