Skip to content

fix(maticjs): retry transient network errors via a shared retryTransient helper - #481

Merged
MaximusHaximus merged 1 commit into
masterfrom
worktree-retry-transient-fetch
Jun 26, 2026
Merged

MaximusHaximus merged 1 commit into
masterfrom
worktree-retry-transient-fetch

Conversation

@MaximusHaximus

Copy link
Copy Markdown
Contributor

Problem

The config-store fetch in ABIManager.init (via HttpRequest) had no retry. Node.js 19+ keeps HTTP(S) connections alive by default, so when the server closes an idle keep-alive socket, the next request reusing it dies with a transient error — observed as a node-fetch Premature close while reading https://static.polygon.technology/network/mainnet/v1/index.json. Web3SideChainClient.init then masked it as network mainnet - v1 is not supported (fixed in #477 to surface the cause — which is how we caught this). It's intermittent and load-sensitive, so it hit CI ~80% of the time while passing locally.

getReceiptProof already documents and handles this exact failure class (ECONNRESET, …) with a bespoke inline retry — but that logic lived only in proof_util.ts, and its predicate was code-only, so it wouldn't even have matched Premature close (a FetchError whose message, not code, carries the cause).

Fix — one shared helper, no duplicated retry logic

New utils/retry.ts:

  • isTransientNetworkError(err) — the known transient codes (ECONNRESET, ENOTFOUND, ECONNREFUSED, ETIMEDOUT, EPIPE, ERR_STREAM_PREMATURE_CLOSE) plus message-based matching for node-fetch's Premature close / socket hang up (the gap that let this bug through).
  • retryTransient(fn, opts) — full-jitter exponential backoff (defaults preserved from the previous inline implementation: 2 retries, 50 * 2^i capped at 250ms).

Wired in:

  • http_request.ts — get/post wrap their fetch in retryTransient (transient connection failures retried; HTTP-status errors stay non-retried).
  • proof_util.ts — the inline attempt() recursion in getReceiptProof is replaced by retryTransient(() => web3.getTransactionReceipt(hash)). Behaviour preserved, and it now also covers Premature close.

Tests

tests/retry.test.ts (6 cases): classification incl. Premature close; retry-then-succeed; no-retry on application errors; give-up-and-rethrow. Full package suite: 35 passed. Typecheck + lint + webpack build green.

@MaximusHaximus
MaximusHaximus marked this pull request as ready for review June 26, 2026 13:04
@claude

claude Bot commented Jun 26, 2026

Copy link
Copy Markdown

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

shan8851
shan8851 previously approved these changes Jun 26, 2026
@claude

claude Bot commented Jun 26, 2026

Copy link
Copy Markdown

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

The config-store fetch (ABIManager.init -> HttpRequest) had no retry, so a
stale keep-alive socket (Node 19+ keeps HTTP connections alive by default)
surfaced as a node-fetch "Premature close" / ECONNRESET and — masked by
Web3SideChainClient.init — looked like "network mainnet - v1 is not supported".

Extract the retry/backoff + transient-error classification that getReceiptProof
implemented inline into a shared `retryTransient` helper, and use it on both the
metadata fetch and the receipt-proof RPC reads. The shared classifier also
recognises node-fetch's "Premature close" (message-based), which the old inline
predicate — code-only — did not match, so the metadata path is now actually
covered. Full-jitter exponential backoff, defaults preserved from the previous
inline implementation.
@MaximusHaximus
MaximusHaximus force-pushed the worktree-retry-transient-fetch branch from 506f588 to 9dc06a2 Compare June 26, 2026 13:16
@MaximusHaximus
MaximusHaximus merged commit 32aa73c into master Jun 26, 2026
10 checks passed
@MaximusHaximus
MaximusHaximus deleted the worktree-retry-transient-fetch branch June 26, 2026 13:21
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.

2 participants