mastra-ai/mastra · error · HTTPException

Tool is not executable

Error message

Tool is not executable

What it means

A 400 thrown when the resolved tool exists but has no execute function — the tool object lacks the executable capability required by the execution endpoint. Typically indicates the ID resolved to a non-executable artifact or a malformed tool definition.

Source

Thrown at packages/server/src/server/handlers/tools.ts:265

      if (!tool) {
        try {
          tool = mastra.getToolById(toolId);
        } catch {
          // tool not found in global registry, continue to agent fallback
        }
      }

      // Fallback: search dynamically-resolved agent tools (toolsResolver)
      if (!tool) {
        tool = await findToolInAgents(mastra, toolId, requestContext);
      }

      if (!tool) {
        throw new HTTPException(404, { message: 'Tool not found' });
      }

      if (!tool?.execute) {
        throw new HTTPException(400, { message: 'Tool is not executable' });
      }

      const { data } = bodyParams;

      validateBody({ data });

      let result;
      if (isVercelTool(tool)) {
        result = await (tool as any).execute(data);
      } else {
        result = await tool.execute(data!, {
          mastra,
          requestContext,
          // TODO: Pass proper tracing context when server API supports tracing
          tracingContext: { currentSpan: undefined },
          ...(runId
            ? {
                workflow: {

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Add an execute function to the tool definition (via createTool) so it is runnable server-side.
  2. Verify you registered/exported the actual tool object, not a metadata fragment.
  3. Pick a different, executable tool if this one is intentionally definition-only.

Example fix

// before
export const weatherTool = createTool({ id: 'weather', inputSchema, outputSchema }); // no execute
// after
export const weatherTool = createTool({
  id: 'weather',
  inputSchema,
  outputSchema,
  execute: async ({ context }) => fetchWeather(context),
});
Defensive patterns

Strategy: type-guard

Validate before calling

const tool = await api.get(`/api/tools/${toolId}`);
if (!tool || typeof tool.execute !== 'function') {
  throw new Error(`Tool ${toolId} exists but has no execute implementation`);
}

Type guard

function isExecutableTool(tool: unknown): tool is { id: string; execute: (args: never) => Promise<unknown> } {
  return !!tool && typeof (tool as any).execute === 'function';
}

Try / catch

try {
  return await api.post(`/api/tools/${toolId}/execute`, { data });
} catch (e) {
  if (e.status === 400 && /not executable/i.test(e.message)) return null;
  throw e;
}

Prevention

When it happens

Trigger: POST execute where the resolved tool (from registeredTools, mastra, or agents toolsResolver) has tool?.execute undefined — e.g. a tool created with createTool missing an execute handler, or a descriptor/placeholder object rather than a real tool.

Common situations: Tools defined only as schemas/specs (e.g. for client-side generation) without an execute implementation; exporting the wrong symbol (metadata instead of tool); partial upgrade where tool shape changed.

Related errors


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