vercel/ai · error · Error

Could not find tool approval request ${request.approvalId}.

Error message

Could not find tool approval request ${request.approvalId}.

What it means

applyToolApprovalResponse locates the tool part referenced by an approval request (by partIndex and toolCallId) before writing the approval response. If the part is missing, is not a tool part, or the toolCallId no longer matches, it throws. This protects against applying a stale approval to the wrong tool call.

Source

Thrown at packages/tui/src/agent-tui-runner.ts:658

      input: part.input,
      providerExecuted: part.providerExecuted,
      messageId: message.id,
      partIndex: index,
    });
  }

  return requests;
}

function applyToolApprovalResponse(
  message: UIMessage,
  request: AgentTUIToolApprovalRequest,
  response: AgentTUIToolApprovalResponse,
) {
  const part = message.parts[request.partIndex];

  if (!part || !isToolUIPart(part) || part.toolCallId !== request.toolCallId) {
    throw new Error(
      `Could not find tool approval request ${request.approvalId}.`,
    );
  }

  part.state = 'approval-responded';
  part.approval = {
    id: request.approvalId,
    approved: response.approved,
    ...(response.reason ? { reason: response.reason } : {}),
  };
}

function formatStreamError(error: unknown) {
  if (error instanceof Error) {
    return error.message;
  }

  if (typeof error === 'string') {

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Apply the approval response once, against the current message state.
  2. Re-derive requests from the latest responseMessage instead of caching them.
  3. Guard the stored request list and clear it after responding.
  4. Match by toolCallId against current parts before calling applyToolApprovalResponse.

Example fix

// before
const request = staleRequests[0];
applyToolApprovalResponse(message, request, response);
// after
const current = findPendingToolApprovalRequests(latestMessage)
  .find(r => r.approvalId === approvalId);
if (current) applyToolApprovalResponse(latestMessage, current, response);
Defensive patterns

Strategy: validation

Validate before calling

function isRequestStillValid(message, request) {
  const part = message.parts[request.partIndex];
  return Boolean(part && isToolUIPart(part) && part.toolCallId === request.toolCallId);
}

Type guard

function isPendingApproval(message, request) {
  const part = message.parts[request.partIndex];
  return Boolean(
    part && isToolUIPart(part) && part.toolCallId === request.toolCallId,
  );
}

Try / catch

try {
  applyToolApprovalResponse(message, request, response);
} catch (error) {
  if (error.message.includes('Could not find tool approval request')) {
    // refresh requests from the latest message and retry once
  } else throw error;
}

Prevention

When it happens

Trigger: Responding to an AgentTUIToolApprovalRequest after the message's parts changed — e.g. the message was updated/reset, the part index shifted, or the response is applied twice.

Common situations: Duplicate approval responses; stale requests captured before a rerender; messages replaced during streaming so partIndex is outdated; applying responses out of order.

Related errors


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