Tool Invocation Missing Result Error
Issue
When using generateText()
or streamText()
, you may encounter the error "ToolInvocation must have a result" when a tool without an execute
function is called.
Cause
The error occurs when you define a tool without an execute
function and don't provide the result through other means (like useChat
's onToolCall
or addToolResult
functions).
Each time a tool is invoked, the model expects to receive a result before continuing the conversation. Without a result, the model cannot determine if the tool call succeeded or failed and the conversation state becomes invalid.
Solution
You have two options for handling tool results:
- Server-side execution using tools with an
execute
function:
const tools = { weather: tool({ description: 'Get the weather in a location', parameters: z.object({ location: z .string() .describe('The city and state, e.g. "San Francisco, CA"'), }), execute: async ({ location }) => { // Fetch and return weather data return { temperature: 72, conditions: 'sunny', location }; }, }),};
- Client-side execution with
useChat
(omitting theexecute
function), you must provide results usingaddToolResult
:
import { useChat } from '@ai-sdk/react';import { DefaultChatTransport, lastAssistantMessageIsCompleteWithToolCalls,} from 'ai';
const { messages, sendMessage, addToolResult } = useChat({ // Automatically submit when all tool results are available sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls,
// Handle tool calls in onToolCall onToolCall: async ({ toolCall }) => { if (toolCall.toolName === 'getLocation') { const result = await getLocationData();
// Important: Don't await inside onToolCall to avoid deadlocks addToolResult({ tool: 'getLocation', toolCallId: toolCall.toolCallId, output: result, }); } },});
// For interactive UI elements:const { messages, sendMessage, addToolResult } = useChat({ transport: new DefaultChatTransport({ api: '/api/chat' }), sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls,});
// Inside your JSX, when rendering tool calls:<button onClick={() => addToolResult({ tool: 'myTool', toolCallId, // must provide tool call ID output: { /* your tool result */ }, }) }> Confirm</button>;
Whether handling tools on the server or client, each tool call must have a corresponding result before the conversation can continue.