Skip to content

fix: abort generateText on webSearch timeout#306

Merged
dcramer merged 1 commit intomainfrom
fix/websearch-timeout-abort-v2
May 7, 2026
Merged

fix: abort generateText on webSearch timeout#306
dcramer merged 1 commit intomainfrom
fix/websearch-timeout-abort-v2

Conversation

@sentry-junior
Copy link
Copy Markdown
Contributor

@sentry-junior sentry-junior Bot commented May 7, 2026

Problem

JUNIOR-1HError: webSearch timed out (15 events, 10 users, ongoing since 2026-04-10)

When webSearch times out after 60s, the underlying generateText() call to the AI Gateway continues running in the background indefinitely. No AbortController signal is passed, so the HTTP request is never cancelled. Retries compound the problem since each one leaves behind another orphaned request leaking connections and memory.

Root Cause

withTimeout() uses Promise.race to implement the deadline, but the losing promise (generateText) is never told to stop. The same file (network.ts) already uses AbortController correctly for fetchTextWithRedirects — the search tool just wasn't wired the same way.

Fix

network.tswithTimeout

  • Added optional onTimeout callback for post-timeout cleanup.
  • Reject fires first, then onTimeout runs in a try/catch — so the abort can never race the timeout error, and a throwing cleanup callback cannot break timeout semantics.

search.tscreateWebSearchTool

  • Create an AbortController per search call.
  • Pass abortSignal: controller.signal to generateText() so the AI SDK cancels the underlying HTTP request on abort.
  • Wire onTimeout: () => controller.abort() so the abort fires immediately after the timeout rejection.

Tests

  • Added test verifying the AbortSignal is aborted on timeout.
  • Added test verifying the signal stays clean on successful search.
  • Added test verifying timeout is still correctly reported even when the abort cleanup throws.
  • Added abortSignal assertion to the happy-path call-shape test.

Supersedes #304 (closed due to shallow-clone force-push breaking branch history).

Closes JUNIOR-1H

When webSearch times out after 60s, the underlying generateText() call
was left running in the background indefinitely — leaking connections
and memory. Retries compounded the problem since each retry left behind
another orphaned request.

Fix:
- Pass AbortController signal to generateText so the HTTP request is
  actually cancelled when the timeout fires.
- Add onTimeout callback to withTimeout for clean post-rejection
  cleanup. Reject fires first so abort can never race the timeout
  error; callback is wrapped in try/catch so cleanup failures cannot
  break timeout semantics.

Closes JUNIOR-1H

Co-Authored-By: Claude (anthropic/claude-opus-4.6) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 7, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
junior-docs Ready Ready Preview, Comment May 7, 2026 7:04pm

Request Review

@dcramer dcramer merged commit a16b3a3 into main May 7, 2026
13 checks passed
@dcramer dcramer deleted the fix/websearch-timeout-abort-v2 branch May 7, 2026 19:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant