Web3.js: Misleading error message: "Can not send value to non-payable contract method or constructor"

Created on 11 Mar 2019  路  4Comments  路  Source: ChainSafe/web3.js

Description

Receive "Can not send value to non-payable contract method or constructor instead!" error when calling a function that is definitely payable. Also, the error itself grammatically makes no sense. Also, the error itself makes no sense since the method _is_ payable.

Expected behavior

Shouldn't receive error about non-payable method or constructor if the method or constructor is payable.

Actual behavior

Returns above error.

Steps to reproduce the behavior

Works fine with [email protected], but throws aforementioned error in ...-beta.48.

Using the following solidity in order to query an offchain API using Provable (Oraclize):

pragma solidity ^0.5.0;

import "./oraclizeAPI.sol";

contract DieselPrice is usingOraclize {

    uint public dieselPriceUSD;

    event LogNewDieselPrice(string price);
    event LogNewOraclizeQuery(string description);

    constructor() public {
        update(); // First check at contract creation...
    }

    function __callback(bytes32 myid, string memory result) public {
        require(msg.sender == oraclize_cbAddress());
        emit LogNewDieselPrice(result);
        dieselPriceUSD = parseInt(result, 2); // Let's save it as cents...
        // Now do something with the USD Diesel price...
    }

    function update() public payable {
        emit LogNewOraclizeQuery("Oraclize query was sent, standing by for the answer...");
        oraclize_query("URL", "xml(https://www.fueleconomy.gov/ws/rest/fuelprices).fuelPrices.diesel");
    }
}

And the following javascript to test that the update() function should fail if the contract's balance is zero (because Provable [Oraclize]) requires a fee):

  it('Should revert on second query attempt due to lack of funds', async () => {
    const expErr = 'revert'
    try {
      await methods
        .update()
        .send({
          from: address,
          gas: gasAmt
        })
      assert.fail('Update transaction should not have succeeded!')
    } catch (e) {
      assert.isTrue(
        e.message.startsWith(`${PREFIX}${expErr}`),
        `Expected ${expErr} but got ${e.message} instead!`
      )
    }
  })
}

...results in the above error. Tests pass as expected with beta47 but not beta48. Worse, the error message makes no sense since it's clear there is:

  • a) No value being sent in the methods.update().send(...params) function
  • b) The update() method in the contract is payable.

Error Logs

"Can not send value to non-payable contract method or constructor instead!"

Full Example

You can find the above Provable (Oraclize) example with Truffle tests in the repo here. Simply pull it, install its dependencies and then install [email protected] & follow the README to run the tests.

Versions

  • web3.js: -beta.48
  • nodejs: 10.15.0
  • ethereum node: Ganache/TestRPC
bug

Most helpful comment

I can confirm this behavior. @gskapka did misread the test result. The error is in fact Can not send value to non-payable contract method or constructor, and "instead" is part of the assert:

`Expected ${expErr} but got ${e.message} instead!`

I tested with beta.47 and it threw the same message, however. @nivida So it is highly likely that the problem arose with some other release.

All 4 comments

"Can not send value to non-payable contract method or constructor instead!"

This error message does not exist in the web3.js project the error message would be:
"Can not send value to non-payable contract method or constructor"

Works fine with [email protected], but throws aforementioned error in ...-beta.48

The difference between version beta.48 and beta.47 is just a fix for the custom provider handling and the return value handling of a contract call. I've tested it with a freshly deployed contract and called several methods without any error popping up.

I can confirm this behavior. @gskapka did misread the test result. The error is in fact Can not send value to non-payable contract method or constructor, and "instead" is part of the assert:

`Expected ${expErr} but got ${e.message} instead!`

I tested with beta.47 and it threw the same message, however. @nivida So it is highly likely that the problem arose with some other release.

I can confirm this behavior. @gskapka did misread the test result

Oops! Hoisted by my own petard! Glad @OFRBG could confirm the behavioural difference however.


The problem clarified:

Receive Can not send value to non-payable contract method or constructor error when calling a contract method that __is__ payable, whilst also sending __no__ value.

Thanks for the additional details! I will fix and release it asap.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

oktapodia picture oktapodia  路  3Comments

gabmontes picture gabmontes  路  3Comments

mishell-trickster picture mishell-trickster  路  3Comments

zamoore picture zamoore  路  3Comments

ragnu picture ragnu  路  3Comments