{"record":{"id":"37b6c44379a47418","repo":"vercel/ai","slug":"tool-toolcall-toolname-not-found","errorCode":null,"errorMessage":"Tool \"${toolCall.toolName}\" not found","messagePattern":"Tool \"(.+?)\" not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/workflow/src/workflow-agent.ts","lineNumber":2949,"sourceCode":"\nfunction getToolCallbackMessages(\n  messages: LanguageModelV4Prompt,\n): ModelMessage[] {\n  const withoutAssistantToolCall =\n    messages.at(-1)?.role === 'assistant' ? messages.slice(0, -1) : messages;\n  return withoutAssistantToolCall as unknown as ModelMessage[];\n}\n\nasync function executeTool(\n  toolCall: { toolCallId: string; toolName: string; input: unknown },\n  tools: ToolSet,\n  messages: LanguageModelV4Prompt,\n  context?: unknown,\n  download?: DownloadFunction,\n  sandbox?: SandboxSession,\n): Promise<WorkflowToolExecutionResult> {\n  const tool = tools[toolCall.toolName];\n  if (!tool) throw new Error(`Tool \"${toolCall.toolName}\" not found`);\n  if (typeof tool.execute !== 'function') {\n    throw new Error(\n      `Tool \"${toolCall.toolName}\" does not have an execute function. ` +\n        `Client-side tools should be filtered before calling executeTool.`,\n    );\n  }\n  // Input is already parsed and validated by streamModelCall's parseToolCall\n  const parsedInput = toolCall.input;\n  let toolResult: unknown;\n\n  try {\n    // Extract execute function to avoid binding `this` to the tool object.\n    // If we called `tool.execute(...)` directly, JavaScript would bind `this`\n    // to `tool`, which contains non-serializable properties like `inputSchema`.\n    // When the execute function is a workflow step (marked with 'use step'),\n    // the step system captures `this` for serialization, causing failures.\n    const { execute } = tool;\n    toolResult = await execute(parsedInput, {","sourceCodeStart":2931,"sourceCodeEnd":2967,"githubUrl":"https://github.com/vercel/ai/blob/69428b1f8b037e4d118fb4853428d5c4e620493c/packages/workflow/src/workflow-agent.ts#L2931-L2967","documentation":"executeTool looks up the requested tool by name in the provided tools map and throws when no tool with that name is registered. This happens when the model emitted a tool call that is not part of the tools passed to the workflow agent run.","triggerScenarios":"The model emits a tool call whose toolName is not present in the `tools` object passed to executeTool / the agent step; stale tool registry after changing tools; tool name mismatch between model configuration and execution context.","commonSituations":"Renaming a tool on the client but not the agent definition; multi-step conversations where earlier tool definitions were removed; passing a subset of tools to executeTool; typos in tool names.","solutions":["Ensure every tool the model may call is present in the `tools` map passed to the agent/workflow step.","Log toolCall.toolName and compare against Object.keys(tools) to find the mismatch.","Filter invalid tool calls out of the prompt before execution (client-side tools are handled separately).","Sync tool definitions between client and server if they are defined in two places."],"exampleFix":"// before\nawait executeTool({ toolCall, tools: { getWeather } }); // model called 'search'\n// after\nawait executeTool({ toolCall, tools: { getWeather, search } });","handlingStrategy":"validation","validationCode":"if (!tools[toolCall.toolName]) {\n  throw new Error(`Tool \"${toolCall.toolName}\" is not registered; available: ${Object.keys(tools).join(', ')}`);\n}","typeGuard":"function isRegisteredTool(tools: Record<string, unknown>, name: string) {\n  return Object.prototype.hasOwnProperty.call(tools, name);\n}","tryCatchPattern":"try {\n  await executeTool({ toolCall, tools });\n} catch (e) {\n  if (e instanceof Error && e.message.endsWith('not found')) {\n    console.error(`Unknown tool ${toolCall.toolName}; known: ${Object.keys(tools)}`);\n    // append tool-result error message to the conversation instead of crashing\n  } else throw e;\n}","preventionTips":["Keep client and server tool registries in sync from a single shared definition module.","Log available tool names when configuring the agent.","Filter model tool calls against the registry before executing.","Add tests that simulate model calls for every registered tool."],"tags":["tools","workflow","agent"],"backgroundTag":"tool-not-found","analyzedSha":"69428b1f8b037e4d118fb4853428d5c4e620493c","analyzedAt":"2026-08-30T12:32:21.016Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}