That is due to how [Ethers][1] dynamically handles transactions. If you need to call a method that does not change the state of a smart contract (i.e. `test1` and `test3`), Ethers uses a _call_. _Calls_ are used to read the smart contract's state, and they follow a specific execution path that leads to particular results or errors (https://docs.ethers.io/v5/api/utils/logger/#errors--call-exception). In particular, **the tx is not sent to the blockchain** - it's a read, it's not needed - so the execution result is returned directly to the client. In your case, `test1` and `test3` both return: `Error: call revert exception; VM Exception while processing transaction: reverted with reason string "BadHappened" [ See: https://links.ethers.org/v5-errors-CALL_EXCEPTION ]...` When calling a method that can _potentially_ change the blockchain's state, a **tx is actually sent to the blockchain**, it is mined, and then the result is read from the tx's receipt. There you can find the custom error. And this is why only `test2` reverts with `Error: VM Exception while processing transaction: reverted with custom error 'aCustomError("BadHappened")'` [1]: https://ethers.io