Error message
Provided chainId "1" must match the active chainId "137"
Also printed as
- Cannot sign messages for chainId "1", because MetaMask is switching networks.
dApps receive it as a JSON-RPC error from `eth_signTypedData_v4` (MetaMask returns code -32603 with this text). The numbers are your domain's and the wallet's chain IDs. While MetaMask is switching networks the request fails with "Cannot sign messages for chainId …, because MetaMask is switching networks.".
MetaMask (eth_signTypedData_v3/v4) — validation in @metamask/signature-controller
What it means
The EIP-712 `domain.chainId` of the typed data differs from the network the wallet is currently connected to, and MetaMask refuses to show the signature request. The rule protects users: the chain ID is part of what gets signed, and a signature for another chain could be replayed there. The first number is the dApp's `domain.chainId`, the second the wallet's active chain, both in decimal.
Why it happens
The dApp hard-codes chainId
commonA domain built with `chainId: 1` (or a test network ID) while users connect on Polygon, Base, Arbitrum… The signature request fails for every user not on that chain.
The user switched networks after the dApp read the chain
commonThe dApp cached the chain ID at connection time and did not listen to `chainChanged`. The next signature request carries the stale value.
chainId as a string that parses differently
occasionalMetaMask parses string chain IDs as hex only with a `0x` prefix. `"89"` is decimal 89, not Polygon's 0x89 (137).
How to fix it
- 1.
Build the domain from the wallet's current chain
Read the chain ID right before signing and pick the verifying contract deployed on that chain.
ts const chainId = await walletClient.getChainId(); // viem // const chainId = Number(await provider.send("eth_chainId", [])); // ethers / raw EIP-1193 const domain = { name: "Example DEX", version: "1", chainId, verifyingContract: dexAddressFor(chainId) }; - 2.
Or switch the wallet to the required chain
When the order or permit is only valid on one chain, request a network switch first (`wallet_switchEthereumChain`), then sign.
ts // If the signature is only valid on one chain (the verifying contract lives there), ask the wallet to switch. await walletClient.switchChain({ id: 1 }); const signature = await walletClient.signTypedData({ account, domain, types, primaryType: "Order", message });