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
- Implement execute on the tool so it returns the tool's result.
- If the tool is only meant for descriptions/schema, replace the workflow step with a plain StepParams step implementing the logic.
- 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
- Never register abstract/base tool instances that expect subclasses to define execute.
- Validate the full tool surface (schemas + execute) at registration/boot time.
- Avoid casting tools to any, which hides the missing execute from the type checker.
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
- Tool '${entry.toolId}' not found for workflow step '${entry.
- Dynamic workflow references tool "${entry.toolId}" which is
- Tool must have input and output schemas defined
- Workflow ${workflowId} not found
- Workflow ID is required
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/17cac288a0c1c37a.
Report an issue: GitHub.