BlockchainSolidity5 min readUpdated

Why Solidity uint8 Wraps Modulo 256 in 0.7 but Reverts in 0.8

By Mudassir Khan — Agentic AI Consultant & AI Systems Architect, Islamabad, Pakistan

Cover illustration for: Why Solidity uint8 Wraps Modulo 256 in 0.7 but Reverts in 0.8

Quick answer

Why does Solidity uint8 wrap to modulo 256 in 0.7 but revert in 0.8? Solidity 0.7 inherited C-style overflow semantics: arithmetic on fixed-width unsigned integers silently wraps around. Solidity 0.8 changed this — every arithmetic operation now has a built-in overflow check that reverts. The 0.8 design treats overflow as a bug by default and requires the developer to opt into wrapping behaviour with an unchecked block.

Section 01 · Semantics

What is actually happening

A uint8 is an 8-bit unsigned integer. Its valid range is 0 through 255. When arithmetic falls outside that range, the compiler version determines what happens next.

A uint8 is an 8-bit unsigned integer. Its valid range is 0 through 255. When the arithmetic result of an operation falls outside that range, something has to give:

  • Solidity 0.7: the result is taken modulo 2^8 = 256. So 255 + 1 becomes 0, and 0 - 1 becomes 255. No error, no revert.
  • Solidity 0.8: the EVM-level math is the same — the result still wraps — but Solidity 0.8 emits an extra check after every arithmetic operation, and reverts with Panic(0x11) if the result wrapped.

The change happened because the wrap behaviour caused too many production exploits. Pre-0.8, developers had to import OpenZeppelin's SafeMath library on every contract to get the revert behaviour. Post-0.8, the safe behaviour is the default and the wrap behaviour is the opt-in. See the uint type reference for the full range table across uint8 through int256.

Section 02 · Opt-in Wrap

The unchecked block

When you actually want the wrap — gas-tight loops, ring buffers, certain hashing tricks — wrap the expression in unchecked { }.

solidity
// Solidity 0.8+ — explicit opt-in to wrap behaviour
uint8 x = 255;
unchecked {
    x = x + 1; // x is now 0, no revert
}

The unchecked block is the documented escape hatch. Auditors expect to see it whenever wrap behaviour is intended; a bare arithmetic operation in 0.8 that depends on wrapping is a bug almost every time. See loop gas optimization for the most common production use case.

Unchecked propagates through the block

Every arithmetic expression inside unchecked { } skips the overflow check — not just the one you intended to wrap. Keep unchecked blocks as narrow as possible: one expression, one variable, never a whole function body.

Section 03 · Migration

The migration trap

Most code does not depend on wrapping. But two patterns do, and they break silently on compiler upgrade.

When migrating a 0.7 contract to 0.8, every arithmetic operation in the codebase becomes a candidate for the migration trap. Two patterns are the most common offenders:

  • Counter loops with deliberate modulo. A loop that walks a ring buffer using i = (i + 1) % BUFFER_SIZE is fine. A loop that depends on uint8 i; i++; wrapping to 0 after 255 is silent in 0.7 and reverts in 0.8.
  • Gas-tight increment loops. for (uint i; i < length; i++) is roughly 80 gas per iteration in 0.8 due to the overflow check. The idiomatic 0.8 fix is to use unchecked { ++i; } inside the loop body.

The safest migration path: compile under 0.8, run the full test suite, fix every failing revert by either accepting the safer semantics or explicitly opting into unchecked.

solidity
// Before migration (0.7) — depends on wrap
for (uint8 i = 0; i < 255; i++) {
    // i wraps at 255+1 = 0 — infinite loop risk
}

// After migration (0.8) — safe and cheap
for (uint256 i; i < length;) {
    // loop body here
    unchecked { ++i; }
}

Section 04 · Context

Why this query keeps showing up

The pattern is predictable: unexpected zero counter mid-debug leads straight here.

Developers paste a snippet like solidity 0.7 uint8 overflow wraps modulo 256 into Google when they hit unexpected behaviour mid-debug. The pattern usually goes: “my counter just hit zero out of nowhere” → “what does Solidity actually do on overflow?” → paste.

The answer is the compiler version. Check the pragma solidity line at the top of the contract first. If it says ^0.8.0 or higher, the wrap is a revert. If it says ^0.7.x or lower, the wrap is silent. There is no other configuration.

The Solidity storage layout visualizer can help you see how small integer types are packed in storage, which is the other common reason developers reach for uint8 in the first place.

FAQ

Frequently asked questions

Common follow-up questions about uint8 overflow behaviour across Solidity versions.

Does this apply to uint256 as well?

Yes. Every fixed-width unsigned integer in Solidity behaves the same way. uint256 wraps at 2^256 - 1 in 0.7 and reverts there in 0.8. The reason uint8 shows up in search queries more is that hitting the boundary at 255 happens frequently in real code; hitting it at 2^256-1 only happens in pathological cases.

What about int8 and other signed integers?

Same compiler-version semantics. The math differs (two's complement wrap), but the 0.7 vs 0.8 transition is identical: silent wrap pre-0.8, panic revert in 0.8+, unchecked to opt back into wrap.

Is SafeMath still useful in 0.8?

No. The library is now redundant — every arithmetic operation gets the same check that SafeMath previously added. OpenZeppelin recommends removing the import in 0.8+ for gas savings.

When should I actually use unchecked?

Three legitimate cases: gas-tight loop counters, ring-buffer index math, and hand-rolled hashing where you want bit-level wrap behaviour. Outside those cases, the safer default is almost always correct.

Written by Mudassir Khan

Agentic AI consultant and AI systems architect based in Islamabad, Pakistan. CEO of Cube A Cloud. 38+ agentic AI launches delivered for global founders and CTOs.

View Blockchain Development serviceSee ChainTrust Compliance Engine case study

Related service

Blockchain Development

See scope & pricing →

Related case study

ChainTrust Compliance Engine

Read case study →

More on this topic

Need an AI systems architect?

Book a 30-minute architecture call. I will sketch the high-level design for your use case and give you an honest view of the trade-offs.

Book a strategy call →