{"record":{"id":"a1a8b2b0d6bcd5c8","repo":"vercel/ai","slug":"tool-call-part-toolcallid-not-found","errorCode":null,"errorMessage":"Tool call ${part.toolCallId} not found.","messagePattern":"Tool call (.+?) not found\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/ai/src/generate-text/convert-language-model-content.ts","lineNumber":71,"sourceCode":"              part.data.type === 'data'\n                ? part.data.data\n                : part.data.url.toString(),\n            mediaType: part.mediaType,\n          }),\n          ...(part.providerMetadata != null\n            ? { providerMetadata: part.providerMetadata }\n            : {}),\n        });\n        break;\n      }\n\n      case 'tool-call': {\n        const toolCall = toolCalls.find(\n          toolCall => toolCall.toolCallId === part.toolCallId,\n        );\n\n        if (toolCall == null) {\n          throw new Error(`Tool call ${part.toolCallId} not found.`);\n        }\n\n        contentParts.push(toolCall);\n        break;\n      }\n\n      case 'tool-result': {\n        const toolCall = toolCalls.find(\n          toolCall => toolCall.toolCallId === part.toolCallId,\n        );\n\n        // Handle deferred results for provider-executed tools (e.g., programmatic tool calling).\n        // When a server tool (like code_execution) triggers a client tool, the server tool's\n        // result may be deferred to a later turn. In this case, there's no matching tool-call\n        // in the current response.\n        if (toolCall == null) {\n          const tool = getOwn(tools, part.toolName);\n          const supportsDeferredResults =","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/vercel/ai/blob/69428b1f8b037e4d118fb4853428d5c4e620493c/packages/ai/src/generate-text/convert-language-model-content.ts#L53-L89","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Fix the mock/custom provider so every tool result is preceded by a tool-call part with the same toolCallId","Verify toolCallId generation matches between call and result parts in custom providers","Update the provider package to the latest version in case of a known stream bug","Capture the raw stream to identify which part references the missing id"],"exampleFix":"// before\ntoolResults: [{ toolCallId: 'call_1', result: 42 }] // no matching toolCall\n// after\ntoolCalls: [{ toolCallId: 'call_1', toolName: 'get', input: {} }],\ntoolResults: [{ toolCallId: 'call_1', result: 42 }]","handlingStrategy":"validation","validationCode":"const callIds = new Set(content.filter(p => p.type === 'tool-call').map(p => p.toolCallId));\nconst orphan = content.filter(p => p.type === 'tool-result' && !callIds.has(p.toolCallId));\nif (orphan.length) throw new Error('tool results without matching calls: ' + orphan.map(o => o.toolCallId));","typeGuard":"function hasMatchingToolCalls(content: { type: string; toolCallId?: string }[]): boolean {\n  const ids = new Set(content.filter(p => p.type === 'tool-call').map(p => p.toolCallId!));\n  return content.filter(p => p.type === 'tool-result').every(p => ids.has(p.toolCallId!));\n}","tryCatchPattern":"try {\n  return await generateText({ model, prompt });\n} catch (e) {\n  if (e instanceof Error && /Tool call .* not found/.test(e.message)) {\n    console.error('stream inconsistency; check provider/mock content order');\n  }\n  throw e;\n}","preventionTips":["In mock providers, always emit tool-call parts before their results","Keep provider packages up to date","Verify toolCallId consistency when synthesizing stream chunks"],"tags":["streaming","tool-call","provider-response","inconsistent-state"],"backgroundTag":"orphan-tool-result","analyzedSha":"69428b1f8b037e4d118fb4853428d5c4e620493c","analyzedAt":"2026-08-30T12:32:21.016Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}