`require`, `revert` and `assert` all undo state changes. Custom errors encode a selector plus arguments instead of a string, so they are cheaper and machine-readable.
error InsufficientBalance(uint256 have, uint256 need); if (bal < amt) revert InsufficientBalance(bal, amt);
Use `require` for input and state validation, custom errors for anything your UI must decode, and `assert` only for invariants that should be impossible to break.