vercel/ai · error

Tool call ${part.toolCallId} not found.

Error message

Tool call ${part.toolCallId} not found.

What it means

While converting LanguageModelV* content into step content, a 'tool-result' (or related) part references a toolCallId that is not present among the tool calls emitted earlier in the same response. convertLanguageModelContent throws a plain Error because a tool result without its call is an inconsistent model stream. This typically indicates a provider/stream bug or corrupted stream data.

Source

Thrown at packages/ai/src/generate-text/convert-language-model-content.ts:71

              part.data.type === 'data'
                ? part.data.data
                : part.data.url.toString(),
            mediaType: part.mediaType,
          }),
          ...(part.providerMetadata != null
            ? { providerMetadata: part.providerMetadata }
            : {}),
        });
        break;
      }

      case 'tool-call': {
        const toolCall = toolCalls.find(
          toolCall => toolCall.toolCallId === part.toolCallId,
        );

        if (toolCall == null) {
          throw new Error(`Tool call ${part.toolCallId} not found.`);
        }

        contentParts.push(toolCall);
        break;
      }

      case 'tool-result': {
        const toolCall = toolCalls.find(
          toolCall => toolCall.toolCallId === part.toolCallId,
        );

        // Handle deferred results for provider-executed tools (e.g., programmatic tool calling).
        // When a server tool (like code_execution) triggers a client tool, the server tool's
        // result may be deferred to a later turn. In this case, there's no matching tool-call
        // in the current response.
        if (toolCall == null) {
          const tool = getOwn(tools, part.toolName);
          const supportsDeferredResults =

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Fix the mock/custom provider so every tool result is preceded by a tool-call part with the same toolCallId
  2. Verify toolCallId generation matches between call and result parts in custom providers
  3. Update the provider package to the latest version in case of a known stream bug
  4. Capture the raw stream to identify which part references the missing id

Example fix

// before
toolResults: [{ toolCallId: 'call_1', result: 42 }] // no matching toolCall
// after
toolCalls: [{ toolCallId: 'call_1', toolName: 'get', input: {} }],
toolResults: [{ toolCallId: 'call_1', result: 42 }]
Defensive patterns

Strategy: validation

Validate before calling

const callIds = new Set(content.filter(p => p.type === 'tool-call').map(p => p.toolCallId));
const orphan = content.filter(p => p.type === 'tool-result' && !callIds.has(p.toolCallId));
if (orphan.length) throw new Error('tool results without matching calls: ' + orphan.map(o => o.toolCallId));

Type guard

function hasMatchingToolCalls(content: { type: string; toolCallId?: string }[]): boolean {
  const ids = new Set(content.filter(p => p.type === 'tool-call').map(p => p.toolCallId!));
  return content.filter(p => p.type === 'tool-result').every(p => ids.has(p.toolCallId!));
}

Try / catch

try {
  return await generateText({ model, prompt });
} catch (e) {
  if (e instanceof Error && /Tool call .* not found/.test(e.message)) {
    console.error('stream inconsistency; check provider/mock content order');
  }
  throw e;
}

Prevention

When it happens

Trigger: A provider stream emits a tool-result/tool-approval part with a toolCallId never seen in a preceding tool-call part; custom mock streams in tests emit results before/outside their calls; provider sends duplicated or mismatched call ids after streaming interruptions.

Common situations: Building mock providers with hand-written content arrays that omit the tool-call part; provider API changes or beta endpoints with inconsistent ids; partial stream capture where the tool-call chunk was lost.

Related errors


AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/a1a8b2b0d6bcd5c8. Report an issue: GitHub.