{"record":{"id":"6c6271687b84cd43","repo":"vercel/ai","slug":"received-tool-input-delta-for-missing-tool-call-wi","errorCode":null,"errorMessage":"Received tool-input-delta for missing tool call with ID \"${chunk.toolCallId}\". Ensure a \"tool-input-start\" chunk is sent before any \"tool-input-delta\" chunks.","messagePattern":"Received tool-input-delta for missing tool call with ID \"(.+?)\"\\. Ensure a \"tool-input-start\" chunk is sent before any \"tool-input-delta\" chunks\\.","errorType":"exception","errorClass":"UIMessageStreamError","httpStatus":null,"severity":"error","filePath":"packages/ai/src/ui/process-ui-message-stream.ts","lineNumber":627,"sourceCode":"                  toolCallId: chunk.toolCallId,\n                  toolName: chunk.toolName,\n                  state: 'input-streaming',\n                  input: undefined,\n                  providerExecuted: chunk.providerExecuted,\n                  title: chunk.title,\n                  toolMetadata: chunk.toolMetadata,\n                  providerMetadata: chunk.providerMetadata,\n                });\n              }\n\n              write();\n              break;\n            }\n\n            case 'tool-input-delta': {\n              const partialToolCall = state.partialToolCalls[chunk.toolCallId];\n              if (partialToolCall == null) {\n                throw new UIMessageStreamError({\n                  chunkType: 'tool-input-delta',\n                  chunkId: chunk.toolCallId,\n                  message:\n                    `Received tool-input-delta for missing tool call with ID \"${chunk.toolCallId}\". ` +\n                    `Ensure a \"tool-input-start\" chunk is sent before any \"tool-input-delta\" chunks.`,\n                });\n              }\n\n              partialToolCall.text += chunk.inputTextDelta;\n\n              const { value: partialArgs } = await parsePartialJson(\n                partialToolCall.text,\n              );\n\n              if (partialToolCall.dynamic) {\n                updateDynamicToolPart({\n                  toolCallId: chunk.toolCallId,\n                  toolName: partialToolCall.toolName,","sourceCodeStart":609,"sourceCodeEnd":645,"githubUrl":"https://github.com/vercel/ai/blob/69428b1f8b037e4d118fb4853428d5c4e620493c/packages/ai/src/ui/process-ui-message-stream.ts#L609-L645","documentation":"Partial tool calls are registered by 'tool-input-start' into `state.partialToolCalls` keyed by toolCallId. A 'tool-input-delta' for an unregistered toolCallId throws this UIMessageStreamError. Streaming tool input incrementally requires the start chunk to create the partial tool call first.","triggerScenarios":"A UI message stream emits 'tool-input-delta' whose toolCallId never appeared in a 'tool-input-start' (or whose partial call was already finished by 'tool-input-available'), e.g. in custom stream writers or resumed streams.","commonSituations":"Custom tool-input streaming implementations skipping tool-input-start; toolCallId mismatches between start and delta chunks; resuming streams after the tool-input-start was consumed; duplicate deltas after tool input completion.","solutions":["Send 'tool-input-start' with the same toolCallId before streaming any 'tool-input-delta'.","Ensure toolCallIds match exactly between tool-input-start and every tool-input-delta.","On stream resume, re-emit tool-input-start (or restart the tool call) before continuing deltas.","Catch UIMessageStreamError for tool-input-delta and skip orphan deltas in tolerant consumers."],"exampleFix":"// before\nwriter.write({ type: 'tool-input-delta', toolCallId: 'call_1', inputTextDelta: '{\"city\"' });\n// after\nwriter.write({ type: 'tool-input-start', toolCallId: 'call_1', toolName: 'getWeather' });\nwriter.write({ type: 'tool-input-delta', toolCallId: 'call_1', inputTextDelta: '{\"city\"' });\nwriter.write({ type: 'tool-input-available', toolCallId: 'call_1', input: { city: 'SF' } });","handlingStrategy":"validation","validationCode":"const openToolCalls = new Set<string>();\nfunction assertToolCallOpen(toolCallId: string) {\n  if (!openToolCalls.has(toolCallId)) throw new Error(`tool-input-delta without tool-input-start for ${toolCallId}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await processUIMessageStream(...);\n} catch (e) {\n  if (e instanceof Error && /tool-input-delta for missing tool call/.test(e.message)) {\n    console.warn('Malformed stream: orphan tool-input-delta', e.message);\n  } else throw e;\n}","preventionTips":["Emit tool-input-start before any tool-input-delta with the same toolCallId.","Stop streaming deltas once tool-input-available has been emitted.","Reuse SDK writer helpers for tool input streaming.","Persist start chunks and replay them on resume."],"tags":["streaming","tool-calls","ui-message-stream","protocol-violation"],"backgroundTag":"missing-stream-chunk","analyzedSha":"69428b1f8b037e4d118fb4853428d5c4e620493c","analyzedAt":"2026-08-30T12:32:21.016Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}