{"record":{"id":"954819ebcf29b3ba","repo":"vercel/ai","slug":"model-tried-to-call-unavailable-tool-toolname-954819","errorCode":null,"errorMessage":"Model tried to call unavailable tool '${toolName}'. Available tools: ${availableTools.join(', ')}.","messagePattern":"Model tried to call unavailable tool '(.+?)'\\. Available tools: (.+?)\\.","errorType":"exception","errorClass":"NoSuchToolError","httpStatus":null,"severity":"error","filePath":"packages/ai/src/generate-text/parse-tool-call.ts","lineNumber":181,"sourceCode":"\nasync function doParseToolCall<TOOLS extends ToolSet>({\n  toolCall,\n  tools,\n}: {\n  toolCall: LanguageModelV4ToolCall;\n  tools: TOOLS;\n}): Promise<TypedToolCall<TOOLS>> {\n  const toolName = toolCall.toolName as keyof TOOLS & string;\n\n  const tool = getOwn(tools, toolName);\n\n  if (tool == null) {\n    // provider-executed dynamic tools are not part of our list of tools:\n    if (toolCall.providerExecuted && toolCall.dynamic) {\n      return await parseProviderExecutedDynamicToolCall(toolCall);\n    }\n\n    throw new NoSuchToolError({\n      toolName: toolCall.toolName,\n      availableTools: Object.keys(tools),\n    });\n  }\n\n  const schema = asSchema(tool.inputSchema);\n\n  // when the tool call has no arguments, we try passing an empty object to the schema\n  // (many LLMs generate empty strings for tool calls with no arguments)\n  const parseResult =\n    toolCall.input.trim() === ''\n      ? await safeValidateTypes({ value: {}, schema })\n      : await safeParseJSON({ text: toolCall.input, schema });\n\n  if (parseResult.success === false) {\n    throw new InvalidToolInputError({\n      toolName,\n      toolInput: toolCall.input,","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/vercel/ai/blob/69428b1f8b037e4d118fb4853428d5c4e620493c/packages/ai/src/generate-text/parse-tool-call.ts#L163-L199","documentation":"NoSuchToolError with the list of available tools, thrown when the model called a tool name that does not exist in the provided `tools` map (and the call is not a provider-executed dynamic tool). Includes `availableTools` so you can compare names.","triggerScenarios":"Model emits toolName 'get_weather' but tools defines 'getWeather'; tools passed to a different call/site than the one being parsed; key rename after refactor; multi-step where later steps lack the tools option.","commonSituations":"Typos or casing mismatch between model output and tool keys; renames in provider prompt docs; passing tools conditionally; agent frameworks stripping tools between steps; model hallucinating a similar tool name.","solutions":["Compare error.toolName with error.availableTools and fix the tools key spelling/casing to match what the model calls.","Ensure the same `tools` object is passed to every generateText/streamText step/agent invocation.","Update the system prompt to reference the exact tool names defined in tools.","Catch NoSuchToolError and instruct the model about available tools in a follow-up request."],"exampleFix":"// before\nconst tools = { getCurrentWeather: tool({ ... }) };\n// model calls \"get_current_weather\" -> NoSuchToolError\n// after\nconst tools = { get_current_weather: tool({ ... }) };","handlingStrategy":"validation","validationCode":"const available = Object.keys(tools);\nif (available.length === 0) throw new Error('tools map must not be empty');\n// verify prompt-referenced tool names exist:\nfor (const name of referencedToolNames) {\n  if (!available.includes(name)) throw new Error(`prompt references unknown tool: ${name}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await generateText({ model, prompt, tools });\n} catch (e) {\n  if (NoSuchToolError.isInstance(e)) {\n    console.error(`model called \"${e.toolName}\", available: ${e.availableTools?.join(', ')}`);\n  } else throw e;\n}","preventionTips":["Keep tool keys in one shared constant/module and reference them in prompts.","Grep prompts for tool names and diff against Object.keys(tools) in tests.","Pass the identical tools object to every step of multi-step flows."],"tags":["tool-calling","naming","configuration"],"backgroundTag":"unknown-tool-name","analyzedSha":"69428b1f8b037e4d118fb4853428d5c4e620493c","analyzedAt":"2026-08-30T12:32:21.016Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}