nautechsystems/nautilus_trader · error
mul_div_rounding_up failed
Error message
mul_div_rounding_up failed
What it means
get_next_sqrt_price_from_amount0_rounding_up computes the next sqrt price when adding token0, using mul_div_rounding_up(numerator, sqrt_price_x96, denominator). The expect panics when that operation fails, i.e. the multiplication numerator * sqrt_price_x96 overflows even after the overflow-safe fallback check, or the denominator arithmetic wraps (denominator < numerator).
Source
Thrown at crates/model/src/defi/tick_map/sqrt_price_math.rs:108
sqrt_price_x96: U160,
liquidity: u128,
amount: U256,
add: bool,
) -> U160 {
if amount.is_zero() {
return sqrt_price_x96;
}
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"
);View on GitHub (pinned to 18893faf8b)
Solutions
- Bound the swap amount so the resulting price stays within representable U160/Q96.64 range before calling get_next_sqrt_price_from_input.
- Replace expect with error propagation (anyhow) so callers can reject the swap rather than panic.
- Validate pool sqrt_price_x96 sanity (within Q64.96 bounds) before simulation.
Example fix
// before
let result = FullMath::mul_div_rounding_up(numerator, sqrt_price_x96, denominator)
.expect("mul_div_rounding_up failed");
// after
let result = FullMath::mul_div_rounding_up(numerator, sqrt_price_x96, denominator)
.ok_or_else(|| anyhow::anyhow!("next sqrt price computation overflowed"))?; Defensive patterns
Strategy: validation
Validate before calling
let max = max_swap_amount_for_price(sqrt_price_x96);
if amount > max { return Err(anyhow!("amount exceeds representable next price")); } Type guard
fn price_in_bounds(sqrt_price_x96: U160) -> bool { sqrt_price_x96 >= MIN_SQRT_RATIO && sqrt_price_x96 <= MAX_SQRT_RATIO } Try / catch
match FullMath::mul_div_rounding_up(numerator, sqrt_price_x96, denominator) {
Some(r) => U160::from(r),
None => return Err(anyhow!("next sqrt price overflow")),
} Prevention
- Clamp swap amounts to the MIN/MAX sqrt ratio range.
- Sanity-check pool sqrt price before simulation.
- Exercise swap math with U256-boundary fuzz inputs in CI.
When it happens
Trigger: Trading token0 amounts so extreme that numerator + product overflows (denominator >= numerator fails) yet the code path still reaches the primary mul_div_rounding_up, or sqrt_price_x96 and amount combinations where product/amount no longer equals sqrt_price_x96 but the overflow-checked multiply still cannot be represented.
Common situations: Swap simulations with near-max U256 amounts; corrupted or malicious pool state with an inflated sqrt price; fuzz/tests exercising Uniswap V3's NextInitializedTickWithinOneWord-equivalent math at boundary values.
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
- mul_div overflow
- div_rounding_up failed
- Liquidity addition overflow: x={current}, y={y}, delta={delt
- Contract address should be set in logs
- Contract address should be set in logs
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/785e64beacd59fad.
Report an issue: GitHub.