diff --git a/.changeset/web3-wallet-add-hooks-crash.md b/.changeset/web3-wallet-add-hooks-crash.md
new file mode 100644
index 00000000000..89750b6198c
--- /dev/null
+++ b/.changeset/web3-wallet-add-hooks-crash.md
@@ -0,0 +1,5 @@
+---
+'@clerk/ui': patch
+---
+
+Fix `` crashing with "Rendered fewer hooks than expected" after connecting the last available Web3 wallet.
diff --git a/packages/ui/src/components/UserProfile/Web3Form.tsx b/packages/ui/src/components/UserProfile/Web3Form.tsx
index 39cb0e54f0a..95b18d82444 100644
--- a/packages/ui/src/components/UserProfile/Web3Form.tsx
+++ b/packages/ui/src/components/UserProfile/Web3Form.tsx
@@ -25,15 +25,14 @@ export const AddWeb3WalletActionMenu = () => {
const unconnectedStrategies = enabledStrategies.filter(strategy => {
return !connectedStrategies.includes(strategy) && strategyToDisplayData[strategy];
});
+ const createWeb3Wallet = useReverification((identifier: string) =>
+ user?.createWeb3Wallet({ web3Wallet: identifier }),
+ );
if (unconnectedStrategies.length === 0) {
return null;
}
- const createWeb3Wallet = useReverification((identifier: string) =>
- user?.createWeb3Wallet({ web3Wallet: identifier }),
- );
-
// If the user selects `web3_solana_signature` as their strategy,
// we need to obtain the wallet name to use when connecting and signing the message during the auth flow
//
diff --git a/packages/ui/src/components/UserProfile/__tests__/Web3Section.test.tsx b/packages/ui/src/components/UserProfile/__tests__/Web3Section.test.tsx
index e972492ea2f..d77f735ca7b 100644
--- a/packages/ui/src/components/UserProfile/__tests__/Web3Section.test.tsx
+++ b/packages/ui/src/components/UserProfile/__tests__/Web3Section.test.tsx
@@ -178,4 +178,30 @@ describe('Web3Section', () => {
});
});
});
+
+ // Regression: connecting the last unconnected strategy used to crash the whole
+ // UserProfile with "Rendered fewer hooks than expected", because the action menu
+ // returned early before calling `useReverification`.
+ it('keeps rendering after the last enabled wallet strategy gets connected', async () => {
+ // GIVEN MetaMask is the only enabled web3 strategy and the user has not connected it
+ const withMetamaskEnabled = createFixtures.config(f => {
+ f.withWeb3Wallet();
+ f.withUser({ email_addresses: ['test@clerk.com'] });
+ });
+ const { wrapper, fixtures } = await createFixtures(withMetamaskEnabled);
+ const { getByRole, getByText, queryByRole, rerender } = render(, { wrapper });
+ getByRole('button', { name: /Connect wallet/i });
+
+ // WHEN the user resource updates with a verified MetaMask wallet, as it does after attemptVerification
+ const { fixtures: connected } = await createFixtures(withMetamaskWallet);
+ (fixtures.clerk as any).__internal_lastEmittedResources = {
+ ...(fixtures.clerk as any).__internal_lastEmittedResources,
+ user: connected.clerk.user,
+ };
+ rerender();
+
+ // THEN the wallet is listed and the connect menu is gone
+ getByText(/0x1234...5678/);
+ expect(queryByRole('button', { name: /Connect wallet/i })).toBeNull();
+ });
});