fix(accounts): prevent crash when account tree references orphaned account IDs#41405
Conversation
…count IDs
When state corruption occurs (e.g. after a wallet reset or Snap keyring
reset), the accountTree can contain account IDs that no longer exist in
internalAccounts. Spreading `undefined` via `{ ...accountsById[id] }`
produced an empty object with no `address`, causing
`getWalletIdAndNameByAccountAddress` to throw
`TypeError: Cannot read properties of undefined (reading 'toLowerCase')`.
Fix by filtering orphaned account IDs out of each group in
`getWalletsWithAccounts` so corrupted entries never propagate, and add
optional chaining on `acc.address` in `getWalletIdAndNameByAccountAddress`
as a defensive guard. Adds three regression tests.
Fixes: #41141
Made-with: Cursor
✨ Files requiring CODEOWNER review ✨🔑 @MetaMask/accounts-engineers (2 files, +124 -16)
|
Builds ready [72dff8c]
⚡ Performance Benchmarks (Total: 🟢 18 pass · 🟡 0 warn · 🔴 0 fail)
🌐 Dapp Page Load BenchmarksCurrent Commit: 📄 Localhost MetaMask Test DappSamples: 100 Summary
📈 Detailed Results
Bundle size diffs [🚨 Warning! Bundle size has increased!]
|
Builds ready [a11a9ef]
⚡ Performance Benchmarks (Total: 🟢 18 pass · 🟡 0 warn · 🔴 0 fail)
🌐 Dapp Page Load BenchmarksCurrent Commit: 📄 Localhost MetaMask Test DappSamples: 100 Summary
📈 Detailed Results
Bundle size diffs
|
The filter in getWalletsWithAccounts already guarantees every account in the consolidated wallet data has a valid address, so the ?. guard on acc.address in getWalletIdAndNameByAccountAddress is not needed. Made-with: Cursor
Builds ready [b72ce5d]
⚡ Performance Benchmarks (Total: 🟢 18 pass · 🟡 0 warn · 🔴 0 fail)
🌐 Dapp Page Load BenchmarksCurrent Commit: 📄 Localhost MetaMask Test DappSamples: 100 Summary
📈 Detailed Results
Bundle size diffs [🚀 Bundle size reduced!]
|
|
Builds ready [d779609]
⚡ Performance Benchmarks (Total: 🟢 18 pass · 🟡 0 warn · 🔴 0 fail)
🌐 Dapp Page Load BenchmarksCurrent Commit: 📄 Localhost MetaMask Test DappSamples: 100 Summary
📈 Detailed Results
Bundle size diffs
|



Description
When state corruption occurs (e.g. after a wallet reset or Snap keyring reset), the
accountTreecan contain account IDs that no longer exist ininternalAccounts. IngetWalletsWithAccounts, spreadingundefinedvia{ ...accountsById[missingId] }produces an empty object with noaddressproperty. Downstream,getWalletIdAndNameByAccountAddressthen calls.toLowerCase()onundefined, crashing with:Root cause: The account tree references entropy source IDs that no longer exist in the actual keyrings — typically after a user forgets their password and uses the wallet reset flow, or after using Snaps.
Fix:
getWalletsWithAccounts— added a.filter()before.map()to skip any account ID that has no entry inaccountsById. This prevents orphaned entries from ever entering the consolidated wallet data structure.getWalletIdAndNameByAccountAddress— added optional chainingacc.address?.toLowerCase()as a defensive guard.Changelog
CHANGELOG entry: Fixed a crash that could occur for users with corrupted wallet state after a password reset or Snap keyring usage.
Related issues
Fixes: #41141
Fixes: https://consensyssoftware.atlassian.net/browse/MUL-1633
Manual testing steps
This bug is triggered by corrupted state, which is hard to reproduce manually. The fix is covered by unit tests. To verify:
yarn test:unit ui/selectors/multichain-accounts/account-tree.test.ts— all 75 tests should pass.Pre-merge author checklist
Pre-merge reviewer checklist
Made with Cursor
Note
Low Risk
Low risk defensive change in selectors: it only filters out account IDs that cannot be resolved to
internalAccounts, preventing crashes in downstream lookups. Main impact is that corrupted/stale entries will no longer appear in consolidated wallet/group account lists.Overview
Prevents crashes when
accountTreecontains stale/orphaned account IDs by filtering unresolved IDs out ofgetWalletsWithAccountsbefore building the consolidated wallets/groups structure.Adds regression tests covering: filtering orphaned IDs from groups,
getWalletIdAndNameByAccountAddressnot throwing with corrupted state, and returningnullwhen all referenced accounts are orphaned.Written by Cursor Bugbot for commit d779609. This will update automatically on new commits. Configure here.