100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Error Handling with require, revert, assert

Solidity handles errors by reverting state changes. Learn when to use require for input validation, revert with custom errors for gas-efficient failures, and assert for invariants that must never fail.

Control Flow & FunctionsIntermediate10 min readJul 10, 2026
Analogies

The Revert Model

Solidity error handling is built on the revert model: when an error occurs, all state changes made during the transaction are undone as if it never ran, and remaining gas is returned to the caller. This atomicity is a defining property of smart contracts — a transaction either fully succeeds or leaves the world untouched, so there is no such thing as a half-completed transfer. The three primary tools are require, revert, and assert, and choosing the right one communicates intent and affects gas behavior.

🏏

Cricket analogy: A revert is like a delivery called dead ball — everything that happened is wiped and the score resets to before the ball, so the batsmen gain nothing and lose nothing.

require: Validating Inputs and Conditions

require(condition, "message") checks a condition and, if it is false, reverts with an optional string reason, refunding remaining gas. It is the workhorse for validating function inputs, checking return values of external calls, and enforcing preconditions like sufficient balance or correct caller. Because a failing require refunds unused gas, it is appropriate for expected failure conditions caused by bad input — the caller simply made a mistake and gets their gas back. Before Solidity 0.8, require used the Error(string) mechanism; the string reason is ABI-encoded and stored, which costs gas proportional to its length.

🏏

Cricket analogy: A require is the umpire checking the batsman is ready before the bowler runs in — if not, the delivery is waved away and play simply resets, no penalty to anyone.

revert with Custom Errors

Since Solidity 0.8.4, you can define custom errors with error InsufficientBalance(uint256 available, uint256 required); and trigger them with revert InsufficientBalance(bal, amount);. Custom errors are significantly cheaper than long require strings because only a 4-byte selector (plus any arguments) is encoded, rather than a full string. They also carry structured data that off-chain tools can decode, making failures both cheaper and more informative. The plain revert("message") form still exists and is equivalent to a failing require with that message, useful inside complex if branches where a boolean condition is awkward.

🏏

Cricket analogy: A custom error is like a standardized dismissal code (lbw, caught, bowled) flashed on the scoreboard — a compact signal everyone decodes, versus writing a long paragraph explaining each out.

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract Vault {
    mapping(address => uint256) public balance;
    address public owner = msg.sender;

    // Gas-efficient custom errors with structured data
    error NotOwner(address caller);
    error InsufficientBalance(uint256 available, uint256 required);

    function withdraw(uint256 amount) external {
        // require: input/precondition validation (refunds gas on failure)
        require(amount > 0, "amount must be positive");

        uint256 bal = balance[msg.sender];
        if (bal < amount) {
            // revert with a custom error: cheaper than a long string
            revert InsufficientBalance(bal, amount);
        }

        balance[msg.sender] = bal - amount;

        // assert: an invariant that must never be violated
        assert(balance[msg.sender] <= bal);

        payable(msg.sender).transfer(amount);
    }

    function setOwner(address next) external {
        if (msg.sender != owner) revert NotOwner(msg.sender);
        owner = next;
    }
}

Custom errors (Solidity 0.8.4+) are the recommended default for revert conditions. They encode only a 4-byte selector plus arguments, saving both deployment bytecode (no long strings) and runtime gas, while giving off-chain callers structured, decodable failure data.

assert and Panic Errors

assert(condition) is reserved for checking internal invariants — conditions that should never be false if the code is correct, such as 'total supply never exceeds the cap after a valid mint'. A failing assert raises a Panic(uint256) error rather than an Error(string). Importantly, Solidity 0.8's automatic checks — integer overflow/underflow, division by zero, out-of-bounds array access — also trigger Panic errors. A well-written contract should almost never hit an assert; if it does in production, it signals a bug in the contract itself, not merely bad user input.

🏏

Cricket analogy: An assert is like the scoreboard's internal check that runs-scored never exceeds balls-times-six — if that ever fails, the scoring system itself is broken, not the players.

Do not use assert for input validation — before Solidity 0.8 a failing assert consumed all remaining gas, and it still signals a Panic (contract bug) rather than an expected user error. Use require or custom revert for anything a caller could legitimately trigger, and reserve assert for invariants that indicate a code defect if violated.

  • Solidity uses the revert model: on error, all state changes roll back and remaining gas is refunded, giving atomic all-or-nothing transactions.
  • Use require(condition, msg) to validate inputs and preconditions caused by bad user input.
  • Custom errors (error X(...); revert X(...);) since 0.8.4 are the cheapest, most informative way to fail.
  • revert("msg") is equivalent to a failing require and is handy inside complex if branches.
  • assert is for internal invariants that should never fail; a violation signals a contract bug.
  • Failing assert and Solidity 0.8's overflow/bounds checks raise Panic(uint256); require and revert raise Error(string) or custom errors.
  • Never use assert for input validation — reserve it for conditions that indicate a code defect.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#SolidityStudyNotes#ErrorHandlingWithRequireRevertAssert#Error#Handling#Require#Revert#ErrorHandling#StudyNotes#SkillVeris