Sending fails at gas estimation with "execution reverted"
“The wallet or backend refuses to send: "execution reverted" or "cannot estimate gas", sometimes with only a hex blob, while the same call works in a test or for another account.”
ERROR CODES YOU MAY SEE
A code is a clue. Use its meaning and surrounding evidence to narrow the cause.
CALL_EXCEPTIONethers v6 · libraryExecution reverted during a contract call, gas estimation, or transaction processing.
Inspect the action, revert data, and receipt when available. A failed simulation does not mean a transaction was submitted or mined.
Official reference for CALL_EXCEPTION (opens in new tab)Code definition reviewedINSUFFICIENT_FUNDSethers v6 · libraryThe sending account cannot cover the full transaction cost (gas limit times fee per gas, plus value).
Check the native balance of the account that actually signs, on the chain the provider is connected to. During estimation this is not a contract revert, so decoding revert data will not help.
Official reference for INSUFFICIENT_FUNDS (opens in new tab)Code definition reviewed
THE PRINCIPLE
An estimation revert is a simulated failure, not a sent transaction. The answer is in the revert data and the state you simulated against.
FIRST MOVES
- Capture the revert data, not just the message. Error(string) has selector 0x08c379a0, Panic(uint256) comes from assert and arithmetic checks, and anything else is a custom error: a 4-byte selector plus ABI-encoded arguments.
- Decode it with an ABI that includes the errors of every contract on the call path, such as the token behind a vault. OpenZeppelin 5.x tokens throw ERC20InsufficientAllowance and ERC20InsufficientBalance.
- Re-run the exact request with eth_call: same from, value, and calldata, against latest and an explicit block number. Missing approvals, wrong msg.sender, or zero value explain most reverts.
- Explain differences between simulation and submission: state that changes between blocks (prices, deadlines, nonces, paused flags), block.timestamp, and providers that lag the head.
- Separate non-revert failures. INSUFFICIENT_FUNDS means the signer cannot cover gas plus value; it is not a contract error.
TOOLS: THEN → NOW
PATTERN SNAPSHOT
import { BaseError, ContractFunctionRevertedError } from "viem";
try {
const { request } = await client.simulateContract({
address: vault, abi: [...vaultAbi, ...erc20Abi], // include errors from inner calls
functionName: "deposit", args: [amount, receiver], account,
});
await wallet.writeContract(request);
} catch (err) {
const revert = err instanceof BaseError
? err.walk((e) => e instanceof ContractFunctionRevertedError) : null;
if (revert instanceof ContractFunctionRevertedError) {
log.warn("would revert", revert.data?.errorName, revert.data?.args);
} else throw err;
}CLOSE THE AI. EXPLAIN THIS.
Your estimate reverts with data 0xfb8f41b2... and no message. What do you need to turn it into a readable error, and why might the vault's ABI alone not be enough?HOW IT WORKS UNDERNEATH
RELATED SYMPTOMS
SOURCES
Guide reviewed