vercel/ai · error · ToolCallNotFoundForApprovalError

Tool call "${toolCallId}" not found for approval request "${

Error message

Tool call "${toolCallId}" not found for approval request "${approvalId}".

What it means

Thrown when the model emits a tool-approval-request part whose toolCallId does not match any tool call present in the current step's content. The SDK needs to pair an approval request with its originating tool call, and cannot do so. This indicates a malformed or inconsistent provider response for human-in-the-loop tool approval flows.

Source

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

            dynamic: toolCall.dynamic,
            ...(part.providerMetadata != null
              ? { providerMetadata: part.providerMetadata }
              : {}),
            ...(toolCall.toolMetadata != null
              ? { toolMetadata: toolCall.toolMetadata }
              : {}),
          } as TypedToolResult<TOOLS>);
        }
        break;
      }

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

        if (toolCall == null) {
          throw new ToolCallNotFoundForApprovalError({
            toolCallId: part.toolCallId,
            approvalId: part.approvalId,
          });
        }

        contentParts.push({
          type: 'tool-approval-request' as const,
          approvalId: part.approvalId,
          toolCall,
        });
        break;
      }
    }
  }

  for (const toolOutput of toolOutputs) {
    if (toolCallIdsWithApprovalResponses.has(toolOutput.toolCallId)) {
      toolOutputsWithApprovalResponses.push(toolOutput);

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Inspect the provider response and the reported toolCallId/approvalId; verify the provider emits the tool-call part before the approval request in the same step.
  2. If you reconstruct or trim messages before resuming approval flows, keep the original tool-call parts with matching toolCallId values.
  3. Upgrade @ai-sdk/* packages to matching versions; message content formats changed across majors.
  4. If using a custom provider or proxy, ensure it passes through provider tool-call IDs unchanged.
  5. Catch the error and skip/synthesize a denial for the orphaned approval request.

Example fix

// before: resuming approval after trimming history
messages = messages.filter(m => m.role !== 'assistant' || m.content.some(p => p.type === 'tool-call'));
// after: keep full assistant step containing both tool-call and tool-approval-request parts
messages = trimMessagesButKeepCompleteAssistantSteps(messages);
Defensive patterns

Strategy: try-catch

Validate before calling

// before resuming an approval flow, verify every approval request has a matching tool call
function hasOrphanedApprovals(messages) {
  const ids = new Set();
  for (const m of messages) for (const p of Array.isArray(m.content) ? m.content : [])
    if (p.type === 'tool-call') ids.add(p.toolCallId);
  return messages.flatMap(m => Array.isArray(m.content) ? m.content : [])
    .some(p => p.type === 'tool-approval-request' && !ids.has(p.toolCallId));
}

Type guard

function isToolCallNotFoundForApproval(e) {
  return typeof e === 'object' && e !== null &&
    ToolCallNotFoundForApprovalError.isInstance(e);
}

Try / catch

try {
  const result = await generateText({ ... });
} catch (e) {
  if (ToolCallNotFoundForApprovalError.isInstance(e)) {
    console.warn('Orphaned approval', e.approvalId, 'for tool call', e.toolCallId);
    // drop the orphaned approval and re-run, or synthesize a denial
  } else throw e;
}

Prevention

When it happens

Trigger: Calling generateText/streamText with tool approval (needsApproval) enabled and the provider returns a 'tool-approval-request' content part whose toolCallId is absent from the tool calls collected for that step (e.g. the provider omits or renames the tool-call part, or message history was trimmed so the tool call is missing).

Common situations: Custom/proxy providers that mangle tool-call IDs; replaying or editing stored conversation messages so the tool-call part was dropped; streaming interruptions where the tool call part was lost but the approval request still arrived; version mismatches between message formats.

Related errors


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