SIGN IN SIGN UP

fix(client): retry Node-level transport errors in subscribe/dispatch (#211)

* fix(client): retry Node-level transport errors (ETIMEDOUT, ECONNRESET, ...)

`fal.subscribe()` already retries HTTP 429/502/503/504, but transport-layer
failures (Node fetch wrapping ETIMEDOUT/ECONNRESET/ENOTFOUND/etc. in a
`TypeError: fetch failed`) fell through `isRetryableError` because the
function bailed out on any non-`ApiError`. This mirrors the Python client's
behavior of retrying `httpx.TransportError` and `httpx.TimeoutException`.

Walks the `.cause` chain so it works for both Node's built-in fetch and
implementations like `node-fetch` that set `.code` directly. `AbortError`
is still skipped, so user-cancelled requests are not retried.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(client): bail on AbortError/TimeoutError anywhere in cause chain

Defense-in-depth on top of the previous commit: walk the entire `.cause`
chain looking for `name === 'AbortError'` (manual cancellation) or
`'TimeoutError'` (signal-driven user timeout, e.g. AbortSignal.timeout)
and never retry them. The dispatchRequest layer already short-circuits on
`signal.aborted`, but keeping isRetryableNetworkError honest in isolation
makes it safe to use directly and future-proofs against unusual wrapping.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(client): bump to 1.10.1

Patch release for the transport-error retry fix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
R
Ruslan Kuprieiev committed
442a7571dfa5ea5cf9d2a1192113f207f9bd718c
Parent: f12065b
Committed by GitHub <noreply@github.com> on 5/4/2026, 4:17:59 PM