Skip to content

fix(typescript): handle undici timeout errors and retry network failures#15559

Open
devin-ai-integration[bot] wants to merge 2 commits intomainfrom
devin/1777469251-fix-undici-timeout-handling
Open

fix(typescript): handle undici timeout errors and retry network failures#15559
devin-ai-integration[bot] wants to merge 2 commits intomainfrom
devin/1777469251-fix-undici-timeout-handling

Conversation

@devin-ai-integration
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot commented Apr 29, 2026

Description

Fixes an issue where Node.js's built-in fetch (backed by undici) has a hard 300s headersTimeout that fires before the SDK's timeoutInSeconds, causing generic "fetch failed" errors on long-running requests. Reported upstream at elevenlabs/elevenlabs-js#379.

Changes Made

1. Detect undici timeout errors (Fetcher.ts)

  • Added isTimeoutError() helper that checks for undici-specific error codes (UND_ERR_HEADERS_TIMEOUT, UND_ERR_BODY_TIMEOUT, ETIMEDOUT) in the error cause chain
  • These are now classified as reason: "timeout" instead of reason: "unknown", allowing SDK users to handle them with proper timeout error handling

2. Surface error cause chain (Fetcher.ts)

  • Added getErrorMessageWithCause() helper that walks the error.cause chain to build a descriptive error message including underlying error codes
  • Before: errorMessage: "fetch failed" — opaque, unhelpful
  • After: errorMessage: "fetch failed -> Headers Timeout Error [UND_ERR_HEADERS_TIMEOUT]" — actionable

3. Retry on network-level failures (requestWithRetries.ts)

  • Restructured the retry loop to catch thrown errors from fetch (not just HTTP status codes)
  • Only transient network errors (e.g. ECONNRESET, ECONNREFUSED, EPIPE) are retried with exponential backoff up to maxRetries
  • AbortError (SDK timeout / user abort) and undici timeout errors (UND_ERR_HEADERS_TIMEOUT, UND_ERR_BODY_TIMEOUT, ETIMEDOUT) propagate immediately without retries via isRetryableError() filter
  • Previously, thrown errors from the fetch call bypassed retry logic entirely — the request failed immediately regardless of maxRetries
  • Backward-compatible: existing behavior for HTTP-status-based retries (408, 429, 5xx) is unchanged

Seed snapshots

  • Updated all 211 Fetcher.ts and requestWithRetries.ts seed fixtures across seed/ts-sdk/

Testing

  • pnpm check (biome lint) passes
  • pnpm format passes
  • Seed snapshot files updated to match source templates

Link to Devin session: https://app.devin.ai/sessions/234b24e109924874ab8af5e9b07f397e


Open in Devin Review

- Detect Node.js undici timeout errors (UND_ERR_HEADERS_TIMEOUT,
  UND_ERR_BODY_TIMEOUT, ETIMEDOUT) and classify them as reason: timeout
  instead of reason: unknown
- Include full error cause chain in unknown error messages so underlying
  error codes surface to users instead of just 'fetch failed'
- Retry on network-level failures (connection resets, socket errors) in
  addition to retryable HTTP status codes (408, 429, 5xx)

Co-Authored-By: rishabh <rishabh@buildwithfern.com>
@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

devin-ai-integration[bot]

This comment was marked as resolved.

Timeout and abort errors should propagate immediately without retries.
Only transient network errors (ECONNRESET, ECONNREFUSED, etc.) are retried.

Co-Authored-By: rishabh <rishabh@buildwithfern.com>
@github-actions
Copy link
Copy Markdown
Contributor

SDK Generation Benchmark Results

Comparing PR branch against median of 5 nightly run(s) on main (latest: 2026-04-23T04:59:11Z).

Full benchmark table (click to expand)
Generator Spec main (generator) main (E2E) PR (generator) Delta
ts-sdk square 74s (n=5) 86s (n=5) 68s -6s (-8.1%)

main (generator): generator-only time via --skip-scripts (includes Docker image build, container startup, IR parsing, and code generation — this is the same Docker-based flow customers use via fern generate). main (E2E): full customer-observable time including build/test scripts (nightly baseline, informational). Delta is computed against generator-only baseline.
⚠️ = generation exited with a non-zero exit code (timing may not reflect a successful run).
Baseline from nightly runs on main (latest: 2026-04-23T04:59:11Z). Trigger benchmark-baseline to refresh.
Last updated: 2026-04-29 13:46 UTC

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

0 participants