Skip to content

fix: defer subscriber teardown in emit to prevent WebSocket subscription loss#5132

Open
tenderdeve wants to merge 1 commit into
ethers-io:mainfrom
tenderdeve:fix/websocket-block-subscription-teardown
Open

fix: defer subscriber teardown in emit to prevent WebSocket subscription loss#5132
tenderdeve wants to merge 1 commit into
ethers-io:mainfrom
tenderdeve:fix/websocket-block-subscription-teardown

Conversation

@tenderdeve

Copy link
Copy Markdown

Summary

  • WebSocketProvider silently loses newHeads subscription after once("block") listener fires
  • Root cause: emit() immediately calls subscriber.stop() (which sends eth_unsubscribe) when listener count hits 0. But waitForTransaction re-registers asynchronously after an await getTransactionReceipt(), so the subscription is already gone.
  • Fix: Defer the subscriber cleanup by pollingInterval ms using _setTimeout(), then recheck if listener count is still 0 before stopping. This gives once-listener callbacks time to re-register.
  • Explicit teardown via off() and removeAllListeners() still stops subscribers immediately
  • Deferred timers are cleaned up in destroy()

File: src.ts/providers/abstract-provider.ts

Fixes #5121

Test plan

  • waitForTransaction works correctly across multiple sequential calls
  • WebSocket subscription survives once("block") listener lifecycle
  • provider.destroy() cleans up all timers and subscriptions
  • off("block") still triggers immediate unsubscribe

…ion loss

When a once("block") listener fires and no listeners remain,
emit() immediately calls subscriber.stop(), sending eth_unsubscribe.
But waitForTransaction re-registers asynchronously after an await,
so the subscription is torn down before re-registration can happen.

Defer the cleanup by pollingInterval ms and recheck listener count
before stopping, giving once-listener callbacks time to re-register.
Explicit teardown via off() and removeAllListeners() is unaffected.

Fixes ethers-io#5121
@tenderdeve tenderdeve marked this pull request as ready for review April 28, 2026 10:30
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.

WebSocketProvider silently loses newHeads subscription after once("block") listener fires

1 participant