fix: reject promise when WalletConnect modal is dismissed without pairing#497
Merged
jannik-stacks merged 1 commit intostx-labs:mainfrom Mar 2, 2026
Merged
Conversation
…ring When calling request() with a WalletConnect provider, closing the AppKit modal without completing pairing left the returned promise hanging indefinitely. This happened because connector.connect() internally awaits provider.connect() on the WalletConnect relay, which never resolves when the modal is dismissed. Fix: subscribe to the AppKit modal state via appKit.subscribeState(). When the modal closes and no session was established, the promise is rejected with an error so consuming apps can handle it in a catch block. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
jannik-stacks
approved these changes
Mar 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
When using WalletConnect via
@reown/appkit-universal-connector, closing the AppKit pairing dialog (QR code modal) causes therequest()promise to hang indefinitely becauseconnector.connect()never settles after the dialog is dismissed.This PR fixes that by detecting when the AppKit dialog closes without establishing a session and rejecting the promise with an error, so consuming apps can handle it in a
catchblock.Motivation
The
connector.connect()from@reown/appkit-universal-connectorinternally callsprovider.connect()on the WalletConnect relay, which waits indefinitely for a pairing that will never arrive once the dialog is closed. The dialog closes visually, but nothing tells the underlying promise to stop waiting — leaving any consuming app stuck in a pending state.What was changed
In
WalletConnectProvider.connect()(packages/connect/src/walletconnect/index.ts):appKit.subscribeState()open: false) and no session was established on the provider → reject with an errorHow this impacts application developers
Prior art
Same class of bug as wagmi + MetaMask SDK (wevm/wagmi#4504). Their position was that the wallet SDK should handle rejection properly. In our case,
@reown/appkit-universal-connectordoesn't propagate the dialog dismissal as a rejection, so we work around it at theWalletConnectProviderlayer.Type of Change
Does this introduce a breaking change?
No. The only behavioral change is that a previously-hanging promise now rejects with an error. Any app that was "handling" this by never getting a response will now get a catchable error instead.
Are documentation updates required?
No documentation updates required.
Testing information
Tested manually with an example app consuming
@stacks/connectwith a WalletConnect config.Reproduction steps:
request({ walletConnect: { projectId: '...' } }, 'getAddresses', {})Error: User closed the WalletConnect modalHappy path (verified still works):
request()with WalletConnectAffected code paths:
WalletConnectProvider.connect()→getAddresses()→request()Checklist