vercel/ai · error · NoSuchToolError
Model tried to call unavailable tool '${toolName}'. Availabl
Error message
Model tried to call unavailable tool '${toolName}'. Available tools: ${availableTools.join(', ')}. What it means
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.
Source
Thrown at packages/ai/src/generate-text/parse-tool-call.ts:181
async function doParseToolCall<TOOLS extends ToolSet>({
toolCall,
tools,
}: {
toolCall: LanguageModelV4ToolCall;
tools: TOOLS;
}): Promise<TypedToolCall<TOOLS>> {
const toolName = toolCall.toolName as keyof TOOLS & string;
const tool = getOwn(tools, toolName);
if (tool == null) {
// provider-executed dynamic tools are not part of our list of tools:
if (toolCall.providerExecuted && toolCall.dynamic) {
return await parseProviderExecutedDynamicToolCall(toolCall);
}
throw new NoSuchToolError({
toolName: toolCall.toolName,
availableTools: Object.keys(tools),
});
}
const schema = asSchema(tool.inputSchema);
// when the tool call has no arguments, we try passing an empty object to the schema
// (many LLMs generate empty strings for tool calls with no arguments)
const parseResult =
toolCall.input.trim() === ''
? await safeValidateTypes({ value: {}, schema })
: await safeParseJSON({ text: toolCall.input, schema });
if (parseResult.success === false) {
throw new InvalidToolInputError({
toolName,
toolInput: toolCall.input,View on GitHub (pinned to 69428b1f8b)
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.
Example fix
// before
const tools = { getCurrentWeather: tool({ ... }) };
// model calls "get_current_weather" -> NoSuchToolError
// after
const tools = { get_current_weather: tool({ ... }) }; Defensive patterns
Strategy: validation
Validate before calling
const available = Object.keys(tools);
if (available.length === 0) throw new Error('tools map must not be empty');
// verify prompt-referenced tool names exist:
for (const name of referencedToolNames) {
if (!available.includes(name)) throw new Error(`prompt references unknown tool: ${name}`);
} Try / catch
try {
await generateText({ model, prompt, tools });
} catch (e) {
if (NoSuchToolError.isInstance(e)) {
console.error(`model called "${e.toolName}", available: ${e.availableTools?.join(', ')}`);
} else throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Model tried to call unavailable tool '${toolName}'. No tools
- ACP harnessId must be a stable kebab-case identifier; receiv
- Invalid argument for parameter model: model ${model.provider
- maxEmbeddingsPerCall must be greater than 0
- Unsupported output: ${_exhaustiveCheck}
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/954819ebcf29b3ba.
Report an issue: GitHub.