Skip to main content
Sigvex

Assert Violation Remediation

Validate external inputs with require() and reserve assert() for invariants that should never be false.

Assert Violation Remediation

Overview

assert() is meant for internal invariants that the contract’s own logic guarantees, while require() validates external inputs and state. A reachable assertion failure means the contract can reach a state the developer believed impossible, which signals a logic bug and, on pre-0.8 compilers, burns all remaining gas. The fix is to guard inputs with require() and keep assert() only for conditions that must hold by construction.

Related Detector: Assert Violation

Before (Vulnerable)

function withdraw(uint256 amount) external {
    balances[msg.sender] -= amount;
    assert(totalSupply >= amount); // Can fail if balances and totalSupply diverge
    totalSupply -= amount;
    payable(msg.sender).transfer(amount);
}

After (Fixed)

function withdraw(uint256 amount) external {
    require(balances[msg.sender] >= amount, "Insufficient balance");
    require(totalSupply >= amount, "Supply underflow");
    balances[msg.sender] -= amount;
    totalSupply -= amount;
    payable(msg.sender).transfer(amount);
    assert(totalSupply == _computeExpectedSupply()); // True invariant check
}

Moving the input and state preconditions into require() rejects bad calls cleanly with a refund and a message, before any state change. The remaining assert() now only checks a property that should hold whenever the logic is correct, so a failure genuinely indicates a bug.

Alternative Mitigations

  • Compile with Solidity 0.8+ so a failed assertion reverts with Panic(0x01) and refunds unused gas instead of consuming it all.
  • Use custom errors with require/revert for cheaper, more descriptive input validation.
  • Add invariant tests or fuzzing so genuine assert() conditions are exercised before deployment.

Common Mistakes

  • Using assert() to validate user input or token balances, which are external conditions.
  • Mutating state before checking the precondition, so the contract is left inconsistent on failure.
  • Leaving reachable assertions in pre-0.8 code where failures are a gas-griefing vector.

References