Developer guide

    How to Decode a Failed Transaction and Its Revert Reason

    "Execution reverted" tells you nothing. But the chain almost always returned a reason — a string, a custom error, or a panic code. Here is how each one is encoded and how to read it.

    Three Kinds of Revert

    1. Error(string) — a require message

    0x08c379a0                              // selector for Error(string)
      0000...0020                          // offset
      0000...0014                          // length = 20
      4552433230...                        // "ERC20: bad allowance"

    Decode it as a standard ABI-encoded string after the 4-byte selector.

    2. Panic(uint256) — a language-level failure

    0x4e487b71 + code
    
    0x01  assert(false)
    0x11  arithmetic overflow / underflow
    0x12  division or modulo by zero
    0x21  invalid enum conversion
    0x31  pop() on an empty array
    0x32  array index out of bounds
    0x41  out of memory / too much allocated
    0x51  call to an uninitialized internal function

    3. A custom error

    Since Solidity 0.8.4, contracts revert with typed errors that are far cheaper than strings:

    error InsufficientBalance(uint256 available, uint256 required);
    -> selector = first 4 bytes of keccak256("InsufficientBalance(uint256,uint256)")
    -> followed by the two ABI-encoded arguments

    You need the ABI (or a signature database) to turn that selector back into a name. Explorers that only know Error(string) show a blank reason here.

    Empty revert data

    No data at all usually means: out of gas, a plain revert(), a call to an address with no code, or a failed native-value transfer to a contract without a payable fallback.

    Reading It in Practice

    1. Open a contract page for the contract with its ABI loaded.
    2. Re-attempt the call from the Write tab. Before sending, the transaction is simulated — a revert is caught and decoded against the ABI, so custom errors come back with their name and arguments instead of "execution reverted".
    3. Already have the failed transaction? Paste its calldata into the Calldata Decoder on the Overview tab to confirm which function ran and with what arguments — half of all reverts are simply the wrong arguments.
    4. Use the Events tab with the transaction hash to see what did emit before the failure point.

    The Usual Suspects

    • Missing or too-small ERC-20 allowance — check allowance(owner, spender) before the call.
    • Decimals: sending 1 instead of 1000000000000000000 (or the reverse) trips balance and slippage checks.
    • Access control — onlyOwner / AccessControl reverts because the connected wallet is not the role holder.
    • Deadline or slippage parameters already expired by the time the transaction is mined.
    • Paused contracts: "Pausable: paused" is a require string and decodes cleanly.
    • Calling an implementation directly instead of through its proxy, so all state reads as zero.

    👉 Want the revert reason decoded for you?

    Build a contract page

    Related Guides