{"record":{"id":"e1bd9a61f82e236a","repo":"vercel/ai","slug":"aborterror","errorCode":"AbortError","errorMessage":"Polling was aborted","messagePattern":"Polling was aborted","errorType":"exception","errorClass":"DOMException","httpStatus":null,"severity":"info","filePath":"packages/google/src/interactions/poll-google-interactions.ts","lineNumber":91,"sourceCode":"\n  const startedAt = Date.now();\n  let nextDelayMs = initialDelayMs;\n  const url = `${baseURL}/interactions/${encodeURIComponent(interactionId)}`;\n\n  /*\n   * When the caller aborts, fire a best-effort `POST /interactions/{id}/cancel`\n   * so the run stops billing on Google's side. Wrap every exit path that's\n   * triggered by an abort -- the explicit `abortSignal.aborted` check, the\n   * AbortError thrown by `delay()`, and any AbortError thrown by `getFromApi`.\n   */\n  const cancelOnServer = () =>\n    cancelGoogleInteraction({ baseURL, interactionId, headers, fetch });\n\n  try {\n    while (true) {\n      if (abortSignal?.aborted) {\n        await cancelOnServer();\n        throw new DOMException('Polling was aborted', 'AbortError');\n      }\n\n      if (Date.now() - startedAt > timeoutMs) {\n        throw new Error(\n          `google.interactions: timed out polling interaction ${interactionId} after ${timeoutMs}ms.`,\n        );\n      }\n\n      await delay(nextDelayMs, { abortSignal });\n\n      const {\n        value: response,\n        rawValue: rawResponse,\n        responseHeaders,\n      } = await getFromApi({\n        url,\n        validateUrl: false,\n        headers,","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/vercel/ai/blob/69428b1f8b037e4d118fb4853428d5c4e620493c/packages/google/src/interactions/poll-google-interactions.ts#L73-L109","documentation":"pollGoogleInteractionUntilTerminal polls GET /interactions/{id} until a background Google interaction reaches a terminal status. Before each tick it checks the caller-supplied AbortSignal; if it is already aborted it first fires a best-effort POST /interactions/{id}/cancel so the run stops billing server-side, then throws this AbortError. It is the library's way of honoring cancellation of a long-running background interaction poll.","triggerScenarios":"Calling generateText/streamText (or the interactions API directly) against a background Google interaction while passing an abortSignal, and that signal fires (or is already aborted) while pollGoogleInteractionUntilTerminal is still waiting for a terminal status.","commonSituations":"User cancels a request in a server handler (req.signal / AbortController.timeout), a client disconnects mid-run, or a timeout AbortSignal fires because a deep-research/agent interaction takes many minutes.","solutions":["Catch AbortError (or use error.name === 'AbortError') and treat the interaction as cancelled; the library already sent a server-side cancel.","Increase or restructure the abortSignal lifetime (e.g. use AbortSignal.any with a longer timeout) if cancellation was unintentional.","Pass providerOptions.google.pollingTimeoutMs to raise pollingTimeoutMs so the poll is not cut short before finishing.","Re-poll later by calling the interactions API with the same interactionId if you still need the result."],"exampleFix":"// before\nconst result = await generateText({ model, ... });\n// after\ntry {\n  const result = await generateText({ model, abortSignal: controller.signal, ... });\n} catch (error) {\n  if (error instanceof Error && error.name === 'AbortError') {\n    // interaction was cancelled server-side; handle gracefully\n  } else {\n    throw error;\n  }\n}","handlingStrategy":"try-catch","validationCode":"if (abortSignal?.aborted) { /* skip the call entirely */ }","typeGuard":null,"tryCatchPattern":"try {\n  await pollOrGenerate({ abortSignal });\n} catch (error) {\n  if (error instanceof DOMException && error.name === 'AbortError') {\n    // interaction was cancelled server-side; return a graceful response\n  } else { throw error; }\n}","preventionTips":["Pass an abortSignal only when cancellation is truly desired; use AbortSignal.timeout sized to the expected run duration.","Remember the library sends a server-side cancel on abort — do not also cancel manually.","Account for deep-research interactions taking tens of minutes when sizing signals."],"tags":["abort","polling","cancellation","google-interactions"],"backgroundTag":"request-aborted","analyzedSha":"69428b1f8b037e4d118fb4853428d5c4e620493c","analyzedAt":"2026-08-30T12:32:21.016Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}