nautechsystems/nautilus_trader · error · anyhow::Error

Result would overflow 256 bits

Error message

Result would overflow 256 bits

What it means

mul_div computes floor(a*b/denominator) with full 512-bit intermediate precision. If the 512-bit product's high word is >= the denominator, the quotient would exceed 256 bits, so the function bails instead of returning a wrapped result. This also implicitly rejects denominator == 0.

Source

Thrown at crates/model/src/defi/tick_map/full_math.rs:52

    /// # Errors
    ///
    /// Returns error if `denominator` is zero or the result would overflow 256 bits.
    pub fn mul_div(a: U256, b: U256, mut denominator: U256) -> anyhow::Result<U256> {
        // 512-bit multiply [prod1 prod0] = a * b
        // Compute the product mod 2**256 and mod 2**256 - 1
        // then use the Chinese Remainder Theorem to reconstruct
        // the 512 bit result. The result is stored in two 256
        // variables such that product = prod1 * 2**256 + prod0
        let mm = a.mul_mod(b, U256::MAX);

        // Least significant 256 bits of the product
        let mut prod_0 = a * b;
        let mut prod_1 = mm - prod_0 - U256::from_limbs([u64::from(mm < prod_0), 0, 0, 0]);

        // Make sure the result is less than 2**256.
        // Also prevents denominator == 0
        if denominator <= prod_1 {
            anyhow::bail!("Result would overflow 256 bits");
        }

        ///////////////////////////////////////////////
        // 512 by 256 division.
        ///////////////////////////////////////////////

        // Make division exact by subtracting the remainder from [prod1 prod0]
        // Compute remainder using mul_mod
        let remainder = a.mul_mod(b, denominator);

        // Subtract 256 bit number from 512 bit number
        prod_1 -= U256::from_limbs([u64::from(remainder > prod_0), 0, 0, 0]);
        prod_0 -= remainder;

        // Factor powers of two out of denominator
        // Compute largest power of two divisor of denominator.
        // Always >= 1.
        let mut twos = (-denominator) & denominator;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Reduce a or b before multiplying (factor out common terms with the denominator)
  2. Validate inputs so a*b/denominator fits in U256 before calling
  3. Treat denominator == 0 separately and reject it at the call site
  4. Match Uniswap's solidity behavior: this error mirrors the 'mulDiv overflow' revert

Example fix

// before
let out = mul_div(a, b, denom)?;
// after
anyhow::ensure!(!denom.is_zero(), "denominator must be non-zero");
let out = mul_div(a, b, denom)?; // now only genuine overflow remains possible
Defensive patterns

Strategy: try-catch

Validate before calling

fn mul_div_fits(a: U256, b: U256, denom: U256) -> bool {
    !denom.is_zero() && a.checked_mul(b).map(|p| p / denom < U256::MAX).unwrap_or(false)
}

Try / catch

let out = mul_div(a, b, denom)
    .map_err(|e| MyError::MathOverflow(e.to_string()))?;

Prevention

When it happens

Trigger: Calling mul_div(a, b, denominator) where a*b/denominator >= 2**256 — very large a and b relative to denominator, or denominator zero (which makes prod_1 compare true).

Common situations: Tick/liquidity math on adversarial or corrupted inputs; ported Uniswap V3 FullMath behavior when scaling amounts with extreme ratios; forgetting to normalize amounts before multiplication.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/2749810f7be05ec5. Report an issue: GitHub.