Skip to content

fix(lookupDomains): absorb per-resolver failures#448

Open
wa0x6e wants to merge 1 commit into
masterfrom
fix/fix+stamp-35
Open

fix(lookupDomains): absorb per-resolver failures#448
wa0x6e wants to merge 1 commit into
masterfrom
fix/fix+stamp-35

Conversation

@wa0x6e

@wa0x6e wa0x6e commented May 31, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes STAMP-35 — a context-free Error (1589 occurrences) captured at api.ts:38.

lookupDomains fans out over [ens, shibarium, unstoppableDomains] × chains via Promise.all with no per-resolver error handling. Each resolver captures (with context) or silences its own error and then throws a bare FetchError. That rejected the whole Promise.all and propagated to the api.ts catch-all, which re-captured it as a context-stripped "Error".

Two consequences:

  • Double-reporting — the real error is already captured with context at the resolver layer.
  • Silencing defeatedisSilencedError (subgraph timeouts / 504 / ECONNRESET) suppresses the resolver capture, but the FetchError was still thrown and re-captured at api.ts. That's the bulk of the 1589.

Why this is the right fix

Propagation was correct in the single-resolver origin (#231), where lookupDomains was one ENS call and api.ts was its only error boundary. It was never revisited when the function became a fan-out (#362, #394) — both pure feature additions that didn't touch error handling. The sibling fan-out addressResolvers._call already swallows per-resolver failures with try { … } catch {} for exactly this reason.

This change brings lookupDomains in line with that established pattern: catch each resolver's rejection and return [], so one failing chain no longer rejects the lookup or escapes to api.ts. The api.ts catch remains a genuine safety net for unexpected errors (e.g. getOwner); informative capture + silencing stay at the resolver layer.

Behavior change

Previously, any single resolver/chain failure rejected the whole lookup_domains request → the client got a 500. Now the failing resolver contributes [] and the other chains' results are still returned → the client gets a partial 200.

This path is not cached (no redis/cache layer on lookup_domains, unlike lookup_addresses/resolve_names), so the partial result is per-request only and self-corrects on the next call — there is no risk of caching an incomplete result. The new behavior matches how addressResolvers already treats per-resolver failures.

Test plan

  • Added test/unit/lookupDomains.test.ts (first unit test — fully mocked resolvers; CI runs it via test:coverage) — a resolver rejecting no longer propagates and the other resolvers' results are returned; all-fail returns []. Fails before the change, passes after.
  • yarn typecheck
  • yarn lint

@wa0x6e wa0x6e force-pushed the fix/fix+stamp-35 branch 3 times, most recently from 64f1b6c to a4e4d1f Compare May 31, 2026 14:23
@wa0x6e wa0x6e requested a review from Copilot May 31, 2026 14:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates lookupDomains so per-resolver failures no longer reject the entire lookup_domains request, aligning the behavior with the existing fan-out pattern used by address resolvers.

Changes:

  • Wraps each lookup domain resolver call with a fallback to [] on rejection.
  • Adds unit coverage for partial resolver failure and all-resolvers-fail behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/lookupDomains/index.ts Absorbs individual resolver rejections during domain lookup fan-out.
test/unit/lookupDomains.test.ts Adds mocked resolver tests for partial and total resolver failure scenarios.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

lookupDomains fans out over multiple resolvers (ens, shibarium,
unstoppableDomains) x chains via Promise.all with no per-resolver error
handling. Each resolver captures/silences its own error and then throws a
bare FetchError, which rejected the whole Promise.all and propagated to the
api.ts catch-all, where it was re-captured as a context-free "Error".

This double-reported real errors and defeated the resolvers' isSilencedError
filtering (subgraph timeouts/504s got reported anyway). The single-resolver
origin made propagation correct, but it was never revisited when the function
became a fan-out; the sibling addressResolvers._call already swallows
per-resolver failures for the same reason.

Catch each resolver's rejection and return [] so one failing chain no longer
rejects the lookup or escapes to api.ts, matching the addressResolvers pattern.

Fixes STAMP-35
@tony8713 tony8713 force-pushed the fix/fix+stamp-35 branch from b9dfb64 to 9f1ab5c Compare June 9, 2026 02:35
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