vercel/ai · error · UIMessageStreamError
Received tool-input-delta for missing tool call with ID "${c
Error message
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. What it means
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.
Source
Thrown at packages/ai/src/ui/process-ui-message-stream.ts:627
toolCallId: chunk.toolCallId,
toolName: chunk.toolName,
state: 'input-streaming',
input: undefined,
providerExecuted: chunk.providerExecuted,
title: chunk.title,
toolMetadata: chunk.toolMetadata,
providerMetadata: chunk.providerMetadata,
});
}
write();
break;
}
case 'tool-input-delta': {
const partialToolCall = state.partialToolCalls[chunk.toolCallId];
if (partialToolCall == null) {
throw new UIMessageStreamError({
chunkType: 'tool-input-delta',
chunkId: chunk.toolCallId,
message:
`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.`,
});
}
partialToolCall.text += chunk.inputTextDelta;
const { value: partialArgs } = await parsePartialJson(
partialToolCall.text,
);
if (partialToolCall.dynamic) {
updateDynamicToolPart({
toolCallId: chunk.toolCallId,
toolName: partialToolCall.toolName,View on GitHub (pinned to 69428b1f8b)
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.
Example fix
// before
writer.write({ type: 'tool-input-delta', toolCallId: 'call_1', inputTextDelta: '{"city"' });
// after
writer.write({ type: 'tool-input-start', toolCallId: 'call_1', toolName: 'getWeather' });
writer.write({ type: 'tool-input-delta', toolCallId: 'call_1', inputTextDelta: '{"city"' });
writer.write({ type: 'tool-input-available', toolCallId: 'call_1', input: { city: 'SF' } }); Defensive patterns
Strategy: validation
Validate before calling
const openToolCalls = new Set<string>();
function assertToolCallOpen(toolCallId: string) {
if (!openToolCalls.has(toolCallId)) throw new Error(`tool-input-delta without tool-input-start for ${toolCallId}`);
} Try / catch
try {
await processUIMessageStream(...);
} catch (e) {
if (e instanceof Error && /tool-input-delta for missing tool call/.test(e.message)) {
console.warn('Malformed stream: orphan tool-input-delta', e.message);
} else throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- No tool invocation found for tool call ID "${toolCallId}".
- Received text-delta for missing text part with ID "${chunk.i
- Received text-end for missing text part with ID "${chunk.id}
- Received reasoning-delta for missing reasoning part with ID
- Received reasoning-end for missing reasoning part with ID "$
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/6c6271687b84cd43.
Report an issue: GitHub.