Solidity Custom Errors: Gas‑Efficient Reverts & Practical Adoption
Solidity 0.8.4+ custom errors replace string revert messages with typed errors, reducing gas costs and contract size. This article explains syntax, a worked example, gas comparisons, version limits, and common pitfalls.
12 Jun 2026, 04:10 UTC

The Problem With String Reverts
When a Solidity function reverts with a string message, the literal text is compiled into the contract's bytecode. Every revert copies that string into memory, consuming gas and inflating deployment size. In contracts with many validation checks, these costs compound quickly.
Custom Error Syntax (Solidity 0.8.4+)
Custom errors replace string messages with a named error declaration and typed parameters. The compiler generates a tiny 4‑byte selector; the revert payload consists of the selector and ABI‑encoded arguments—no dynamic memory allocation.
pragma solidity ^0.8.4;contract Token{mapping(address=>uint256)public balanceOf;address public owner;error InsufficientBalance(uint256 requested,uint256 available);error Unauthorized(address caller);constructor(){owner=msg.sender;}function transfer(address to,uint256 amount)external{if(msg.sender!=owner)revert Unauthorized(msg.sender);uint256 bal=balanceOf[msg.sender];if(balGas Cost Comparison
On a local Hardhat network, a revert using a string message costs roughly 3,200 gas, while the same revert with a custom error costs about 1,900 gas. The exact difference depends on the number and types of encoded arguments, but the savings are consistent across many checks.
- String revert: ~3,200 gas
- Custom error revert: ~1,900 gas
Compatibility & Version Constraints
Custom errors are only available from Solidity ^0.8.4. Attempting to compile with 0.8.0–0.8.3 results in the compiler error unknown keyword "error". If a project must support older compilers, retain string reverts or use a pragma override with conditional flags.
Common Pitfalls
- Leaving string reverts in place—negates gas savings and bloats bytecode.
- Expecting human‑readable logs—revert payloads are binary; decode with
ethers.utils.defaultAbiCoder.decodeusing the error signature. - Interface signature mismatches—when an interface declares
error Unauthorized(address caller), all implementing contracts must use the exact parameter types and order. - Trying to catch internal custom errors with try/catch—
try/catchonly captures reverts from external low‑level calls; internal reverts with custom errors propagate unconditionally.
Practical Verification Checklist
- Compile the contract with
pragma solidity ^0.8.4using Hardhat or Foundry. Deploy to a local network. - Trigger a revert by calling
transferwith insufficient balance. Record the gas used from the transaction receipt. - Decode the revert data:
ethers.utils.defaultAbiCoder.decode("uint256","uint256", receipt.logs[0].data)to confirm the selector matchesInsufficientBalance. - Repeat with a string revert and compare gas costs.
- Test interface consistency by declaring the same error in an interface and having a second contract implement it; ensure compilation succeeds only with matching signatures.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.