Search code examples
nearprotocol

NEAR FunctionCallError(HostError(GuestPanic { panic_msg: "panicked at 'Failed to deserialize input from JSON.: Error(\"the account ID is invalid\",


Via CLI, this works: NEAR_ENV=testnet near view dev-1643292007908-55838431863482 nft_tokens_for_owner '{"account_id": "hatchet.testnet"}' and produces the expected result.

I'm now trying to do the same thing via near-api-js but am getting:

Unhandled Runtime Error
Error: Querying [object Object] failed: wasm execution failed with error: FunctionCallError(HostError(GuestPanic { panic_msg: "panicked at 'Failed to deserialize input from JSON.: Error(\"the account ID is invalid\", line: 1, column: 17)', src/contract/nft.rs:65:1" })).
{
  "error": "wasm execution failed with error: FunctionCallError(HostError(GuestPanic { panic_msg: \"panicked at 'Failed to deserialize input from JSON.: Error(\\\"the account ID is invalid\\\", line: 1, column: 17)', src/contract/nft.rs:65:1\" }))",
  "logs": [],
  "block_height": 81208522,
  "block_hash": "5vWcrkVjshewYgLZTTHTZgLN7SF3qpYPovnPUUM1ucBt"
}

Call Stack
JsonRpcProvider.query
node_modules/near-api-js/lib/providers/json-rpc-provider.js (123:0)
async Account.viewFunction
node_modules/near-api-js/lib/account.js (366:0)

I've tried multiple totally separate approaches using near-api-js, and they both result in this error.

My current approach is:

export type NFT = Contract & {
  nft_mint: (args: any, gas: any, depositAmount: any) => Promise<any>; // TODO Add types
  nft_token: (args: any) => Promise<any>;
  nft_tokens_for_owner: (args: any) => Promise<any>;
};

export function getNftContract(account: Account) {
  const contract = new Contract(
    account, // the account object that is connecting
    certificateContractName,
    {
      viewMethods: ['nft_token', 'nft_tokens_for_owner'], // view methods do not change state but usually return a value
      changeMethods: ['nft_mint'], // change methods modify state
    },
  );
  return contract;
}

async function getCertificates(accountId: string): Promise<string[]> {
  const keyStore = new BrowserLocalStorageKeyStore();
  const near = await getNearConnection(keyStore);
  const account = new Account(near.connection, ''); // account_id not required for 'view' call
  const contract = getNftContract(account);
  const response = await (contract as NFT).nft_tokens_for_owner({ account_id: accountId });
  console.log({ account, accountId, response });
  return []; // TODO
}

I'm using testnet, and the accountId I'm passing is hatchet.testnet.


Solution

  • This was a good lesson for me.

    I started looking at the source code of https://docs.rs/near-sdk/3.1.0/src/near_sdk/json_types/account.rs.html#63 and https://docs.rs/near-sdk/3.1.0/src/near_sdk/environment/env.rs.html#816-843

    I homed in on that "The account ID is invalid" error message.

    But I knew I was passing a valid account ID.

    It turns out the problem had nothing to do with NEAR. It was a Next.js / React problem:

    My component's account_id was temporarily empty and trying to call nft_tokens_for_owner too soon (i.e. before account_id had been populated with a value).