{"record":{"id":"dcf0ae0a49f4a375","repo":"mastra-ai/mastra","slug":"tool-is-not-executable","errorCode":null,"errorMessage":"Tool is not executable","messagePattern":"Tool is not executable","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"packages/server/src/server/handlers/tools.ts","lineNumber":265,"sourceCode":"      if (!tool) {\n        try {\n          tool = mastra.getToolById(toolId);\n        } catch {\n          // tool not found in global registry, continue to agent fallback\n        }\n      }\n\n      // Fallback: search dynamically-resolved agent tools (toolsResolver)\n      if (!tool) {\n        tool = await findToolInAgents(mastra, toolId, requestContext);\n      }\n\n      if (!tool) {\n        throw new HTTPException(404, { message: 'Tool not found' });\n      }\n\n      if (!tool?.execute) {\n        throw new HTTPException(400, { message: 'Tool is not executable' });\n      }\n\n      const { data } = bodyParams;\n\n      validateBody({ data });\n\n      let result;\n      if (isVercelTool(tool)) {\n        result = await (tool as any).execute(data);\n      } else {\n        result = await tool.execute(data!, {\n          mastra,\n          requestContext,\n          // TODO: Pass proper tracing context when server API supports tracing\n          tracingContext: { currentSpan: undefined },\n          ...(runId\n            ? {\n                workflow: {","sourceCodeStart":247,"sourceCodeEnd":283,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/server/src/server/handlers/tools.ts#L247-L283","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Add an execute function to the tool definition (via createTool) so it is runnable server-side.","Verify you registered/exported the actual tool object, not a metadata fragment.","Pick a different, executable tool if this one is intentionally definition-only."],"exampleFix":"// before\nexport const weatherTool = createTool({ id: 'weather', inputSchema, outputSchema }); // no execute\n// after\nexport const weatherTool = createTool({\n  id: 'weather',\n  inputSchema,\n  outputSchema,\n  execute: async ({ context }) => fetchWeather(context),\n});","handlingStrategy":"type-guard","validationCode":"const tool = await api.get(`/api/tools/${toolId}`);\nif (!tool || typeof tool.execute !== 'function') {\n  throw new Error(`Tool ${toolId} exists but has no execute implementation`);\n}","typeGuard":"function isExecutableTool(tool: unknown): tool is { id: string; execute: (args: never) => Promise<unknown> } {\n  return !!tool && typeof (tool as any).execute === 'function';\n}","tryCatchPattern":"try {\n  return await api.post(`/api/tools/${toolId}/execute`, { data });\n} catch (e) {\n  if (e.status === 400 && /not executable/i.test(e.message)) return null;\n  throw e;\n}","preventionTips":["Always define execute when creating tools with createTool.","Add a build-time lint/test asserting every exported tool has execute.","Verify you export the tool object itself, not metadata."],"tags":["http-400","tools","validation","tool-definition"],"backgroundTag":"tool-not-executable","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}