fix: make sure pending connection approvals can't get stuck in queue#24040
Conversation
|
CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes. |
…xplanatory comment
| // are added to the list, ensuring previous approvals that weren't rendered for other reasons | ||
| // can be processed. Ideally we can identify all cases where approval fail to render and then remove this dependency. | ||
| pendingApprovals, | ||
| ]); |
There was a problem hiding this comment.
Bug: Duplicate processing when pending approvals change
Adding pendingApprovals to the dependency array without a deduplication mechanism causes the same approval to be processed multiple times. When new approvals are added to the queue, pendingApprovals changes but approvalRequest (first in queue) may remain the same. Without the removed isProcessing guard, each change triggers trackEvent() and navigation.navigate() again for the same approval. This results in duplicate analytics events and potentially duplicate navigation calls. The existing test "does not navigate if still processing" explicitly expects this deduplication behavior, indicating this is a regression.
There was a problem hiding this comment.
Perhaps we should guard against the duplicate trackEvents but I believe the navigation is not an issue since the approvalRequest returned by useApprovalRequest will always be the first in the queue meaning subsequent queued requests while the first one is "processing" will not cause a navigation away from the currently processing approval.
There was a problem hiding this comment.
looking at the dependencies, this shouldn't rerun unless the approvals have changed. Likely not an issue
| // This prevents the queue from getting permanently stuck and handles cases where new approvals | ||
| // are added to the list, ensuring previous approvals that weren't rendered for other reasons | ||
| // can be processed. Ideally we can identify all cases where approval fail to render and then remove this dependency. | ||
| pendingApprovals, |
There was a problem hiding this comment.
If the approvalRequest is already memoised from the full list, then I'm not sure I understand why contriving a dependence on the entire list would make any functional difference?
Since the content of the other approvals is irrelevant, and when one approval request is removed, the useEffect should already re-fire since approvalRequest is now a new reference?
There was a problem hiding this comment.
I think I follow the intent. We have a different bug causing these not to render, so we're just using future approvals as a trigger to re-render and workaround that.
Should we use selectPendingApprovals directly to avoid changing the return of useApprovalRequest?
🔍 Smart E2E Test Selection
click to see 🤖 AI reasoning detailsThe changes modify the
This is a bug fix for the permission approval flow. The component is used in Selected tags:
The test file changes are comprehensive unit tests that verify the new behavior, but E2E tests are needed to ensure the permission approval flow works correctly in real scenarios. |
need review from a confirmations team engineer online
|



Description
These changes are aiming to fix a case of stuck pending approvals we've been running into in our (@MetaMask/wallet-integrations) work on the MMConnect (new SDK). In some edge cases you can get approvals stuck in state where the
isProcessingflag on thePermissionApprovalcomponent is never reset resulting in approvals queued behind it never showing and any subsequent request getting permanently stuck in this queue where nothing is shown and the user has no opportunity to approve or reject anything in the queue. As you can see in the "AFTER" video below, the external browser connection flows we support with the SDK create the possibility of multiple connection requests getting queued (in app browser avoids this since the confirmation blocks further action) since the SDK does not support per origin request rate limiting.Root Cause:
The
PermissionApprovalcomponent used auseRef-basedisProcessingflag to prevent duplicate processing of approval requests. However, in certain edge cases (especially with external browser paths where multiple requests can queue), this flag would never reset tofalse, causing:Solution:
isProcessingref-based guard mechanism that was causing the stuck stateApprovalTypes.REQUEST_PERMISSIONSandeventSourcethat was resetting the flag inappropriatelypendingApprovalListto theuseEffectdependency array so the effect properly re-runs when the approval queue changes for further assurances that the queue does not get permanently stuck.This change allows the component to reactively process approval requests based on the actual state of the approval queue, rather than relying on a ref-based flag that can get out of sync.
Changelog
CHANGELOG entry: Fixed an issue where pending approval requests could become permanently stuck in the queue, preventing users from approving or rejecting subsequent connection requests.
Related issues
Fixes: n/a
Manual testing steps
Screenshots/Recordings
Before
Screen.Recording.2025-12-15.at.3.00.31.PM.mov
After
Screen.Recording.2025-12-15.at.2.54.49.PM.mov
Pre-merge author checklist
Pre-merge reviewer checklist
Note
Remove ref-based processing guard and re-run effect when pending approvals change to avoid stuck permission approvals; add targeted tests and selector-driven mocks.
PermissionApproval.tsx:isProcessingref guard and related reset logic.useSelector(selectPendingApprovals, isEqual)and addpendingApprovalstouseEffectdeps to re-run on queue changes.isEip1193Request.AccountConnectand analytics dispatch intact.PermissionApproval.test.tsx:selectPendingApprovalsandselectAccountsLengthinstead of full background state.getApiAnalyticsPropertiesandgetAllScopesFromPermission.pendingApprovalschanges and after queue is cleared, ensuring navigation occurs; retain analytics and guard-case tests.Written by Cursor Bugbot for commit a11326d. This will update automatically on new commits. Configure here.