Skip to content

fix(provider-utils): retry on Node.js socket termination errors#13668

Open
sidx1024 wants to merge 1 commit intovercel:mainfrom
sidx1024:fix/retry-terminated-network-errors
Open

fix(provider-utils): retry on Node.js socket termination errors#13668
sidx1024 wants to merge 1 commit intovercel:mainfrom
sidx1024:fix/retry-terminated-network-errors

Conversation

@sidx1024
Copy link

Summary

TypeError: terminated and SocketError: other side closed are thrown by Node.js undici when the TCP socket dies mid-response (e.g. during long-running generateText calls with reasoning models). These are transient network errors, but handleFetchError only recognizes "fetch failed" / "failed to fetch", so they fall through as raw errors and are not retried by the exponential backoff logic.

This adds detection for socket termination errors (terminated, other side closed, UND_ERR_SOCKET code) so they are properly wrapped as retryable APICallErrors.

Reproduction

When using generateText with models that have long response times (e.g. gpt-5.2 with reasoningEffort: "high"), the TCP socket can be terminated by intermediate infrastructure. The error surfaces as:

AI_APICallError: Failed to process successful response
  cause: TypeError: terminated
    at Fetch.onAborted (node:internal/deps/undici/undici:12826:53)

or:

SocketError: other side closed
  code: 'UND_ERR_SOCKET'
    at TLSSocket.onHttpSocketEnd (node:internal/deps/undici/undici:6294:28)

Neither error is retried because handleFetchError returns them as-is.

Changes

  • Added isSocketError() helper that matches terminated, other side closed messages and UND_ERR_SOCKET error code
  • Socket errors are now wrapped as APICallError with isRetryable: true
  • Added 3 test cases covering both error shapes

Test plan

  • TypeError: terminated → retryable APICallError
  • SocketError: other side closed (code UND_ERR_SOCKET) → retryable APICallError
  • TypeError: terminated as cause of fetch failed → retryable (existing path, confirmed)
  • All existing tests pass

Fixes #11265
Fixes #9775

TypeError: terminated and SocketError: other side closed are thrown
by Node.js undici when the TCP socket dies mid-response. These are
transient network errors but handleFetchError only recognized
"fetch failed" / "failed to fetch", so they were not wrapped as
retryable APICallErrors.

This adds detection for socket termination errors so they are
properly retried by the exponential backoff logic.

Fixes vercel#11265
Fixes vercel#9775
@tigent tigent bot added ai/provider related to a provider package. Must be assigned together with at least one `provider/*` label bug Something isn't working as documented maintenance CI, internal documentation, automations, etc labels Mar 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai/provider related to a provider package. Must be assigned together with at least one `provider/*` label bug Something isn't working as documented maintenance CI, internal documentation, automations, etc

Projects

None yet

Development

Successfully merging this pull request may close these issues.

isRetryable not set for network errors during response body parsing (ECONNRESET) SocketError: other side closed

1 participant