Skip to content

fix: make sure pending connection approvals can't get stuck in queue#24040

Merged
adonesky1 merged 15 commits into
mainfrom
ad/fix-stuck-pending-approvals
Dec 16, 2025
Merged

fix: make sure pending connection approvals can't get stuck in queue#24040
adonesky1 merged 15 commits into
mainfrom
ad/fix-stuck-pending-approvals

Conversation

@adonesky1

@adonesky1 adonesky1 commented Dec 15, 2025

Copy link
Copy Markdown
Contributor

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 isProcessing flag on the PermissionApproval component 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 PermissionApproval component used a useRef-based isProcessing flag 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 to false, causing:

  1. The current approval to be blocked from processing
  2. All queued approvals behind it to never display
  3. Subsequent requests to get permanently stuck in the queue with no UI shown to the user

Solution:

  • Removed the isProcessing ref-based guard mechanism that was causing the stuck state
  • Removed the early return check for ApprovalTypes.REQUEST_PERMISSIONS and eventSource that was resetting the flag inappropriately
  • Added pendingApprovalList to the useEffect dependency 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

Feature: Permission approval queue handling

  Scenario: Multiple connection requests from external browser
    Given the user has MetaMask Mobile open
    And an external browser (not in-app browser) is used to initiate connection requests
    
    When multiple connection requests are queued in quick succession
    Then all queued approval requests should be displayed sequentially
    And users should be able to approve or reject each request
    And no requests should become permanently stuck in the queue

  Scenario: Approval queue processing after navigation
    Given a connection request is in the approval queue
    And the user navigates away from the approval screen
    
    When the user returns or a new approval request is added
    Then the approval queue should continue processing correctly
    And all pending approvals should be accessible to the user

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

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

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.

  • Approvals
    • PermissionApproval.tsx:
      • Remove isProcessing ref guard and related reset logic.
      • Use useSelector(selectPendingApprovals, isEqual) and add pendingApprovals to useEffect deps to re-run on queue changes.
      • Null-safe check for isEip1193Request.
      • Keep navigation to AccountConnect and analytics dispatch intact.
    • PermissionApproval.test.tsx:
      • Refactor to mock selectPendingApprovals and selectAccountsLength instead of full background state.
      • Mock getApiAnalyticsProperties and getAllScopesFromPermission.
      • Add tests verifying effect re-runs when pendingApprovals changes 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.

@adonesky1 adonesky1 requested a review from a team as a code owner December 15, 2025 20:58
@github-actions

Copy link
Copy Markdown
Contributor

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.

@metamaskbot metamaskbot added the team-wallet-integrations Wallet Integrations team label Dec 15, 2025
@adonesky1 adonesky1 changed the title fix: Open path to get pending approvals unstuck fix: make sure pending connection approvals can't get stuck in queue Dec 15, 2025
Comment thread app/components/Approvals/PermissionApproval/PermissionApproval.tsx Outdated
// 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,
]);

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.

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.

Fix in Cursor Fix in Web

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

looking at the dependencies, this shouldn't rerun unless the approvals have changed. Likely not an issue

Comment thread app/components/Approvals/PermissionApproval/PermissionApproval.tsx
Comment thread app/components/Approvals/PermissionApproval/PermissionApproval.tsx
Comment thread app/components/Approvals/PermissionApproval/PermissionApproval.tsx
Comment thread app/components/Approvals/PermissionApproval/PermissionApproval.tsx
@github-actions github-actions Bot added size-M and removed size-S labels Dec 16, 2025
Comment thread app/components/Approvals/PermissionApproval/PermissionApproval.tsx
ffmcgee725
ffmcgee725 previously approved these changes Dec 16, 2025
Comment thread app/components/Views/confirmations/hooks/useApprovalRequest.ts Outdated
Comment thread app/components/Views/confirmations/hooks/useApprovalRequest.ts Outdated
// 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,

@matthewwalsh0 matthewwalsh0 Dec 16, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🤔

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

addressed in the commits below

@adonesky1 adonesky1 enabled auto-merge December 16, 2025 19:22
@github-actions

Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokeMultiChainPermissions, SmokeWalletPlatform, SmokeNetworkExpansion, SmokeMultiChainAPI
  • Risk Level: medium
  • AI Confidence: 80%
click to see 🤖 AI reasoning details

The changes modify the PermissionApproval component which handles permission approval requests when dApps connect to the wallet. Key changes:

  1. Removed isProcessing ref - Previously used to prevent duplicate processing, but could cause the approval queue to get stuck
  2. Added pendingApprovals selector to useEffect dependencies - Ensures the effect re-runs when the approval queue changes, preventing stuck states
  3. Added optional chaining for approvalRequest?.requestData?.metadata?.isEip1193Request

This is a bug fix for the permission approval flow. The component is used in RootRPCMethodsUI.js which handles all RPC method approvals including dApp connection requests.

Selected tags:

  • SmokeMultiChainPermissions: Directly tests multi-chain permission management which this component handles
  • SmokeWalletPlatform: Tests EVM provider events and dApp connections that trigger permission approvals
  • SmokeNetworkExpansion: Tests chain permission management and initial dApp connections
  • SmokeMultiChainAPI: Tests multi-chain API functionality which uses CAIP-25 permissions (referenced in the code via Caip25EndowmentPermissionName)

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.

View GitHub Actions results

@adonesky1 adonesky1 dismissed matthewwalsh0’s stale review December 16, 2025 19:35

need review from a confirmations team engineer online

@sonarqubecloud

Copy link
Copy Markdown

@adonesky1 adonesky1 added this pull request to the merge queue Dec 16, 2025
Merged via the queue into main with commit fabae6b Dec 16, 2025
94 checks passed
@adonesky1 adonesky1 deleted the ad/fix-stuck-pending-approvals branch December 16, 2025 20:28
@github-actions github-actions Bot locked and limited conversation to collaborators Dec 16, 2025
@metamaskbot metamaskbot added the release-7.62.0 Issue or pull request that will be included in release 7.62.0 label Dec 16, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

release-7.62.0 Issue or pull request that will be included in release 7.62.0 size-M team-wallet-integrations Wallet Integrations team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants