David Atanda Building scalable applications on the web.

Understanding and resolving MetaMask error codes

6 min read 1737

MetaMask gives us the ability to access decentralized applications (dApps) while offering a form of authentication using the MetaMask wallet. It provides a one-click secure login flow that allows us to access the blockchain resources using ethers on the front end. MetaMask abstracts delicate processes like signing transactions while interacting with the blockchain, and provides your MetaMask’s public address to the application.

Thus, as developers, when building these dApps, there are bound to be errors, and these errors should be handled appropriately so both the developers and users can know what is wrong. Because the MetaMask documentation does not have a comprehensive and clear guide to the many types of errors that might come up while working with MetaMask, I have compiled a list here of the most common errors and what they mean.

You can jump to the error codes outlined in this article with the following links:

4001

When trying to connect to the wallet, if a user clicks “Cancel” at any point on this interface and terminates the process, it returns a 4001 error.

Cancel button metamask error

Here’s the JSON structure of the error:

'4001': {
  standard: 'EIP-1193',
  message: 'User rejected the request.',
},

4100

This error occurs when the dApp wants to take action concerning an account that is not authorized.

For instance, to do certain actions like signing a message, you need to first get account permission from MetaMask, using the eth_requestAccounts method:

import { ethers } from "ethers";

const accounts = await ethereum.request({
  method: "eth_requestAccounts",
});

const address = accounts[0];
const provider = new ethers.providers.Web3Provider(ethereum);
const signer = provider.getSigner();
const signature = await signer.signMessage(address);
console.log(signer);

Similarly, to switch the chain of your wallet, you need to use the wallet_switchEthereumChain method, which in turn asks for permission through MetaMask extension:

// switching the chain for MetaMask wallet

await provider.request({
  method: "wallet_switchEthereumChain",
  params: [{ chainId: "0x89" }],
});

If the permission is denied, the wallet returns this error:

We made a custom demo for .
No really. Click here to check it out.

'4100': {
  standard: 'EIP-1193',
  message: 'The requested account and/or method has not been authorized by the user.',
},

4200

MetaMask enables two methods: restricted and unrestricted. These methods allow the dApp to take actions like connecting to the wallet, signing transactions, and adding or switching networks.

This error is returned for the methods that aren’t supported on MetaMask:

'4200': {
  standard: 'EIP-1193',
  message: 'The requested method is not supported by this Ethereum provider.',
},

You can find a link to existing methods here.

4900

This error is returned when the user’s MetaMask wallet is not connected to any chain:

ethereum.on('disconnect', (error) => console.log(error));

It has to do with the disconnect event. This event is triggered when the wallet is disconnected and it becomes unable to submit requests to a chain. Besides disconnection, this can also happen due to network connectivity issues.

Once we emit disconnect, the provider will not accept any new requests until the connection to the chain has been reestablished, which requires reloading the page. You can also use the ethereum.isConnected() method to determine if the provider is disconnected.

Here’s the error’s JSON response:

'4900': {
  standard: 'EIP-1193',
  message: 'The provider is disconnected from all chains.',
},

4901

This error means the user is not connected to the appropriate chain for that transaction. For example, if a transaction requires the user to be on the Polygon chain, and they’re on Harmony or Ethereum blockchain.

One thing to note is that the MetaMask provider allows us to listen to the chainChanged event that listens and acts if the currently connected chain changes:

ethereum.on('chainChanged', (chainId) => {console.log(chainId)});

We submit our RPC requests to the currently connected chain, which makes it important to keep track of the current chain ID by listening for changes. Every chain has its unique chainID, which you can find on Chainlist.

It returns the error if it becomes unable to submit RPC requests to that specific chain:

'4901': {
  standard: 'EIP-1193',
  message: 'The provider is disconnected from the specified chain.',
}

32700

This error is returned if the user sends an incomplete request object to the contract. It can occur if the object sent to the contract does not contain all the data that it requires.

Here’s the JSON response:

 '-32700': {
    standard: 'JSON RPC 2.0',
    message: 'Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text.',
  },

32600

Here, the object is valid, but the structure or properties aren’t correct. It’s somewhat similar to 32700, but in this case, it’s the internal structure that’s not correct.

Here’s the JSON response:

  '-32600': {
    standard: 'JSON RPC 2.0',
    message: 'The JSON sent is not a valid Request object.',
  },

32601

This error is returned if the method specified does not exist at all:

'-32601': {
    standard: 'JSON RPC 2.0',
    message: 'The method does not exist / is not available.',
  },

You can find a link to existing methods here.

32602

We get this error if the arguments passed into an RPC method is incorrect. For instance, when defining the transactionParameters, the from property references accounts[0].

Ordinarily, accounts[0] is supposed to be the user’s wallet address, but in this case, we assign it to an empty array:

 let accounts = [];
  const amountEth = 1
   const paymentAddress = '0x71C7656EC7ab88b098defB751B7401B5f6d8976F'
  const transactionParameters = { from: accounts[0], to: paymentAddress, value: web3.toWei(amountEth, 'ether') };

  function Mint(){
  ethereum.request({ method: 'eth_sendTransaction',  params: [transactionParameters] });

  }

The Mint function will return this particular error because the parameter is clearly invalid:

'-32602': {
    standard: 'JSON RPC 2.0',
    message: 'Invalid method parameter(s).',
  },

32603

This is a blanket error caused by several things. It might be because you’re trying to add a new chain to your wallet (manually or through the dApp) but added the wrong chain data. Or, you’re trying to complete a transaction, but you don’t have enough tokens to pay the gas fee. For instance, if you’re transacting on the Ethereum mainnet, you have to pay gas fees in ETH regardless of whether you’re transacting using other tokens.

Finally, it could be as trivial as not having the latest version of MetaMask.

Here’s the error JSON response:

'-32603': {
    standard: 'JSON RPC 2.0',
    message: 'Internal JSON-RPC error.',
  },

32000

One scenario that can trigger this error is when the contract address used in production is the contract you deployed to the testnet. This is a simple error that we can correct.

Similar to Web2 where we have a dev environment and a production environment, when building dApps, we use testnet to deploy our contract, so we can test it while building without using real ETH on mainnet. As such, the same contract deployed on testnet and mainnet will have different addresses. If you use the wrong address for the chain you’re on, this error is returned.

In general, when dealing with smart contracts, you need params like the contract address, the ABI file, and your signer:

const provider = new ethers.providers.Web3Provider(ethereum);
const signer = provider.getSigner();

const countContract = new ethers.Contract(contractAddress, contractABI, signer);

/*
 * Call the getAllCount method from your Smart Contract
 */
const count = await countContract.getAllCount()

If any of these params are wrong, you’ll most likely get his error, also referred to as a “user input error”:

  '-32000': {
    standard: 'EIP-1474',
    message: 'Invalid input.',
  },

32001

In this case, the resource we’re requesting does not exist on the blockchain. It’s possibly a typo from the client side.

Imagine you’re trying to get info about a non-existent block number on the ETH chain:

import Web3 from 'web3';

const web3 = new Web3(web3Provider);
var block = await web3.eth.getBlock({invalid block number})

You would get this JSON response:

'-32001': {
    standard: 'EIP-1474',
    message: 'Resource not found.',
  },

32002

This error means the requested resource does exist, but it’s currently unavailable at the time of the request. This can occur when we are trying to access a resource that’s currently in use. It can happen on the MetaMask extension when you’re trying to use a particular resource/method, like switching chains when the MetaMask is currently in the process of doing the same.

When building your dApp, you should learn to disable your button once that method has been successfully initiated, so user is not clicking in quick succession.

Here’s this error’s JSON response:

  '-32002': {
    standard: 'EIP-1474',
    message: 'Resource unavailable.',
  },

32003

This error could be a result of many things. It could be because the sender’s address doesn’t exist, insufficient funds, the account is locked, or we can’t sign the transaction. To fix this, make sure everything in your transaction is correct.

The transaction can be rejected if the conditions needed to complete the transaction aren’t satisfied:

  '-32003': {
    standard: 'EIP-1474',
    message: 'Transaction rejected.',
  },

32004

The method is not supported at all. Possibly, it doesn’t exist or there’s just a typographical error:

'-32004': {
    standard: 'EIP-1474',
    message: 'Method not supported.',
  },

32005

This error means the RPC provider has a rate limit that has been exceeded. This issue can occur if the RPC provider endpoint has a rate limit for the number of requests:

  '-32005': {
    standard: 'EIP-1474',
    message: 'Request limit exceeded.',
  },

Also, there’s a fairly common error with the error message “intrinsic gas too low.” It’s simply because the gas limit that’s assigned when initiating the transaction is less than what is required.

This occurs most often in cases where there’s a complex transaction, which can make the gas fee unpredictable:

ethereum
.request({
  method: 'eth_sendTransaction',
  params: [
    {
      from: accounts[0],
      to: '0xbCfDCCDbE7B3D681A1144D25a31e0D4BE869079a',
      value: '0x293434x341af62c0000',
      gasPrice: '0x09184e242',
      gas: '0x2709',
      gasLimit: '0x2723'
    },
  ],
})
.then((txHash) => console.log(txHash))
.catch((error) => console.error);

Conclusion

Congratulations if you’ve made it to the end! We covered a bunch of possible errors and how to deal with them. Now, when building your next dApp, you can easily interpret these errors and fix them without being confused about what caused them in the first place. This can help improve your developer experience dealing with these Web3 technologies.

You can check out more about MetaMask errors from the official resource.

WazirX, Bitso, and Coinsquare use LogRocket to proactively monitor their Web3 apps

Client-side issues that impact users’ ability to activate and transact in your apps can drastically affect your bottom line. If you’re interested in monitoring UX issues, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.https://logrocket.com/signup/

LogRocket is like a DVR for web and mobile apps, recording everything that happens in your web app or site. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.

Modernize how you debug web and mobile apps — .

David Atanda Building scalable applications on the web.

Leave a Reply