nautechsystems/nautilus_trader · error

div_rounding_up failed

Error message

div_rounding_up failed

What it means

In the fallback path of get_next_sqrt_price_from_amount0_rounding_up, div_rounding_up(numerator, fallback_denominator) computes the next price as divRoundingUp(numerator1, numerator1/sqrtPX96 + amount). The expect panics when the division fails — i.e. fallback_denominator is zero, which happens when numerator/sqrt_price_x96 + amount wraps or evaluates to zero due to extreme inputs.

Source

Thrown at crates/model/src/defi/tick_map/sqrt_price_math.rs:116

    let numerator = U256::from(liquidity) << 96;
    let sqrt_price_x96 = U256::from(sqrt_price_x96);
    let product = amount * sqrt_price_x96;

    if add {
        if product / amount == sqrt_price_x96 {
            let denominator = numerator + product;
            if denominator >= numerator {
                // always fit to 160bits
                let result = FullMath::mul_div_rounding_up(numerator, sqrt_price_x96, denominator)
                    .expect("mul_div_rounding_up failed");
                return U160::from(result);
            }
        }

        // Fallback: divRoundingUp(numerator1, (numerator1 / sqrtPX96).add(amount))
        let fallback_denominator = (numerator / sqrt_price_x96) + amount;
        let result = FullMath::div_rounding_up(numerator, fallback_denominator)
            .expect("div_rounding_up failed");

        // Check if result fits in U160
        assert!(result <= U256::from(U160::MAX), "Result overflows U160");
        U160::from(result)
    } else {
        // require((product = amount * sqrtPX96) / amount == sqrtPX96 && numerator1 > product);
        assert!(
            (product / amount) == sqrt_price_x96 && numerator > product,
            "Invalid conditions for amount0 removal: overflow or underflow detected"
        );

        let denominator = numerator - product;
        let result = FullMath::mul_div_rounding_up(numerator, sqrt_price_x96, denominator)
            .expect("mul_div_rounding_up failed");
        U160::from(result)
    }
}

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Clamp swap amounts so the computed next price remains within valid bounds before invoking the function.
  2. Propagate the failure as an error instead of expect, letting swap simulation reject the quote.
  3. Pre-check fallback_denominator != 0 (and no U256 addition overflow) with checked_add.

Example fix

// before
let result = FullMath::div_rounding_up(numerator, fallback_denominator)
    .expect("div_rounding_up failed");
// after
let result = FullMath::div_rounding_up(numerator, fallback_denominator)
    .ok_or_else(|| anyhow::anyhow!("fallback next-sqrt-price division failed (zero denominator)"))?;
Defensive patterns

Strategy: validation

Validate before calling

let fallback_denominator = (numerator / sqrt_price_x96).checked_add(amount)
    .filter(|d| !d.is_zero())
    .ok_or_else(|| anyhow!("degenerate fallback denominator"))?;

Type guard

fn fallback_div_safe(numerator: U256, sqrt_price_x96: U160, amount: U256) -> bool {
    (numerator / U256::from(sqrt_price_x96)).checked_add(amount).map_or(false, |d| !d.is_zero())
}

Try / catch

match FullMath::div_rounding_up(numerator, fallback_denominator) {
    Some(r) => U160::from(r),
    None => return Err(anyhow!("fallback division failed")),
}

Prevention

When it happens

Trigger: Calling get_next_sqrt_price_from_input/output with amount0 values where (numerator / sqrt_price_x96) + amount overflows U256 or yields zero, typically with maximum-size amounts or degenerate sqrt_price_x96 values reaching this branch.

Common situations: Simulating swaps with amounts near U256::MAX; fuzz tests probing the overflow-safe fallback; pools with malformed sqrt prices making numerator/sqrtPX96 huge.

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/9855afdad72e2148. Report an issue: GitHub.