Metamask: Internal JSON-RPC error for state variables
As an Ethers.js user working on deploying a Vyper contract to the Avalanche FUJI testnet using Svelte, you may be experiencing issues accessing certain state variables using your Metamask wallet. In this article, we’ll look at why calling one contract state variable might throw an internal JSON-RPC error, but not another very similar variable.
Understanding JSON-RPC and Ethers.js
Before diving deeper, let’s quickly review the basics:
- JSON-RPC

: A standardized protocol for communicating between nodes in a blockchain network. It provides secure and efficient data transfer.
- Ethers.js: A popular JavaScript library for interacting with Ethereum networks using Web3 or Truffle.
Issue: Internal JSON-RPC Error
When calling a state variable from your contract to a Metamask wallet, you should get an internal JSON-RPC error if the variable is not available. However, in some cases, this error can occur when accessing similar variables in other contracts on the same testnet.
Here is an example of how this might play out:
Let’s say you have a Vyper contract « User » that defines two state variables: « username » and « email ». You want to call the following variables from your Svelte application using Ethers.js in Metamask:
import { ethers } from ' ethers ' ;
const contractAddress = '0x...';
const contractor = [...]; // Your Vyper contract IS NOT
// Connect to the contract on the testnet
async function connectToContract() { .
const provider = new ethers . providers . Web3Provider ( window . ethereum ) ;
return await provider . connect ( contractAddress ) ;
} }
// Call the first state variable from the contract
function getUserInfo() {
const connection = await connectToContract();
try {
const user = await connect.getAccounts()[0];
console.log(user.username); // This should work fine
} catch (error) {
if ( error instanceof ethers . Error ) {
throw error; // Internal JSON-RPC error
} }
} }
} }
// Call the second state variable from the contract
function getProfileInfo() {
const connection = await connectToContract();
try {
const user = await connect.getAccounts()[0];
console . log ( user . email ); // This should also work
} catch (error) {
if ( error instanceof ethers . Error ) {
throw error; // Internal JSON-RPC error
} }
} }
} }
As you can see, the function « getUserInfo() » successfully calls both state variables. However, when using « getProfileInfo() », an internal JSON-RPC error occurs:
// This should not work
function getProfileInfo() {
const connection = await connectToContract();
try {
const user = await connect.getAccounts()[0];
console . log ( user . email ); // Internal JSON-RPC error
} catch (error) {
if ( error instanceof ethers . Error ) {
throw error; // Internal JSON-RPC error
} }
} }
} }
Why the difference?
The issue is related to how Ethers.js handles access to contract state variables. When you call a contract state variable, it tries to retrieve the value using “contractabi” and then calls the corresponding provider function.
However, when accessing similar state variables in other contracts on the same testnet, the getAccounts() method returns an empty array for each new connection. This is because the network has not yet fully connected to the account of the previous contract.
To fix this issue, you can use the following workarounds:
- Use the Ethers.js « connect » function: Instead of calling « getAccounts()[0] », try using « connect().on(‘connected’, (account) => {}) » This will connect to a new node and set an event listener when it is connected.
2.