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

  1. Send 'tool-input-start' with the same toolCallId before streaming any 'tool-input-delta'.
  2. Ensure toolCallIds match exactly between tool-input-start and every tool-input-delta.
  3. On stream resume, re-emit tool-input-start (or restart the tool call) before continuing deltas.
  4. 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

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


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