mastra-ai/mastra · error · Error

Tool ${params.id} does not have an execute function

Error message

Tool ${params.id} does not have an execute function

What it means

This error is thrown at execution time when the tool-wrapped step runs: the step body checks params.execute and throws if the tool has no execute function. The schema guard (1902) runs at creation, but a tool with schemas yet no execute only fails when the step actually executes.

Source

Thrown at packages/core/src/workflows/evented/workflow.ts:690

    scorers: toolOpts?.scorers,
    metadata: toolOpts?.metadata,
    execute: async ({
      inputData,
      mastra,
      requestContext,
      suspend,
      resumeData,
      runId,
      workflowId,
      state,
      setState,
      abortSignal,
      ...obsFields
    }) => {
      const observabilityContext = resolveObservabilityContext(obsFields);
      // Tools receive (input, context) - just call the tool's execute
      if (!params.execute) {
        throw new Error(`Tool ${params.id} does not have an execute function`);
      }

      // Build context matching ToolExecutionContext structure
      const context = {
        mastra,
        requestContext,
        ...observabilityContext,
        abortSignal,
        workflow: {
          runId,
          workflowId,
          state,
          setState,
          suspend,
          resumeData,
        },
      };

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Implement execute on the tool so it returns the tool's result.
  2. If the tool is only meant for descriptions/schema, replace the workflow step with a plain StepParams step implementing the logic.
  3. Add a startup assertion (typeof tool.execute === 'function') to catch the missing execute before a run.

Example fix

// before
const tool = { id: 'sum', inputSchema: z.object({ a: z.number(), b: z.number() }), outputSchema: z.object({ r: z.number() }) };
createStep(tool);

// after
const tool = {
  id: 'sum',
  inputSchema: z.object({ a: z.number(), b: z.number() }),
  outputSchema: z.object({ r: z.number() }),
  execute: async ({ context }) => ({ r: context.a + context.b }),
};
createStep(tool);
Defensive patterns

Strategy: validation

Validate before calling

function assertToolExecutable(tool: { id: string; execute?: unknown }) {
  if (typeof tool.execute !== 'function') {
    throw new Error(`Tool ${tool.id} must implement execute before being used in a workflow`);
  }
}

Type guard

const hasExecute = (t: any): t is { execute: (...args: any[]) => any } =>
  typeof t?.execute === 'function';

Try / catch

try {
  await runStep(toolStep, input);
} catch (e) {
  if (e instanceof Error && e.message.includes('does not have an execute function')) {
    // fall back or fail fast with tool id context
  }
  throw e;
}

Prevention

When it happens

Trigger: Executing a workflow containing a step built via createStep(tool) where tool.execute is undefined — e.g. a tool declaration missing execute, a 'toolset' stub, or a conditionally-attached execute that was never assigned.

Common situations: Abstract/base tool classes where subclasses must implement execute but the base instance was registered; tools used purely for schema inference; mocks in tests lacking execute.

Related errors


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