nautechsystems/nautilus_trader · error
Inverted price denominator exceeds U256 range
Error message
Inverted price denominator exceeds U256 range
What it means
In the same inverted-price branch of `decode_sqrt_price_x96_to_price_tokens_adjusted`, the squared sqrt price (computed as U512) must be narrowed back to U256, and then `price_square * decimal_adjustment` is computed with checked multiplication. The library throws this error when either the U512→U256 narrowing fails or the multiplication overflows U256.
Source
Thrown at crates/model/src/defi/tick_map/sqrt_price_math.rs:404
token1_scalar / token0_scalar
};
let fixed_scalar = FullMath::pow10(FIXED_PRECISION)?;
let divisor_base: U256 = U256::from(1u128) << 192;
let price_raw = if invert {
if decimal_diff >= 0 {
let numerator = divisor_base
.checked_mul(fixed_scalar)
.ok_or_else(|| anyhow::anyhow!("Inverted price numerator exceeds U256 range"))?;
let price_square: U512 = sqrt_price.widening_mul(sqrt_price);
let max_square = U512::from(numerator / decimal_adjustment);
if price_square > max_square {
U256::ZERO
} else {
let price_square = U256::checked_from_limbs_slice(price_square.as_limbs())
.ok_or_else(|| {
anyhow::anyhow!("Inverted price denominator exceeds U256 range")
})?;
let denominator =
price_square
.checked_mul(decimal_adjustment)
.ok_or_else(|| {
anyhow::anyhow!("Inverted price denominator exceeds U256 range")
})?;
FullMath::mul_div(numerator, U256::from(1), denominator)?
}
} else {
let price_square: U512 = sqrt_price.widening_mul(sqrt_price);
anyhow::ensure!(
!price_square.is_zero(),
"Cannot decode inverted price from zero sqrt_price_x96"
);
let numerator = U512::from(divisor_base)
.checked_mul(U512::from(decimal_adjustment))
.and_then(|value| value.checked_mul(U512::from(fixed_scalar)))View on GitHub (pinned to 18893faf8b)
Solutions
- Correct token decimals metadata if decimal_adjustment is inflated by wrong decimals.
- Pre-check `price_square <= U256::MAX / decimal_adjustment` conceptually and return a saturated/clamped price for extreme ratios instead.
- Skip inversion: compute the non-inverted price and take its reciprocal in wider precision.
- Perform the adjustment in U512 and narrow after division.
Example fix
// before
let price = decode_sqrt_price_x96_to_price_tokens_adjusted(sqrt_price, b, q, true)?;
// after
let max_adj = U256::MAX / decimal_adjustment;
if price_square_candidate > max_adj {
return Ok(U256::ZERO); // saturated extreme price, mirroring guard above
}
let price = decode_sqrt_price_x96_to_price_tokens_adjusted(sqrt_price, b, q, true)?; Defensive patterns
Strategy: try-catch
Validate before calling
fn adjustment_fits(price_square: U256, decimal_adjustment: U256) -> bool {
decimal_adjustment.is_zero() || price_square <= U256::MAX / decimal_adjustment
} Try / catch
match decode_sqrt_price_x96_to_price_tokens_adjusted(sqrt_price, b, q, invert) {
Ok(p) if p.is_zero() => {
log::debug!("saturated/extreme price for sqrt_price {sqrt_price}");
handle_extreme_price()
}
Ok(p) => p,
Err(e) if e.to_string().contains("denominator exceeds U256") => fallback_wide_math(),
Err(e) => return Err(e),
} Prevention
- Check token decimals metadata before trusting decimal_adjustment
- Treat a zero returned price as the extreme-ratio signal and guard callers against division by it
- Fall back to U512-based computation for pools near the representable bounds
When it happens
Trigger: Inverted price computation where sqrt_price is large enough that sqrt_price^2 does not fit in U256, or where multiplying the square by the decimal adjustment scalar overflows U256 — despite the earlier `price_square > max_square` guard allowing the path.
Common situations: Extremely high price ratios in pools with asymmetric decimals; edge cases near the guard threshold where the square fits but the adjustment multiplication does not.
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
- Inverted price numerator exceeds U256 range
- Scaled result exceeds 256-bit range
- Decimal exponent {exponent} exceeds U256 range
- Router allowance {allowance} is below the swap amount {} for
- Input token {} balance {balance} is below the swap amount {}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/6fdab83736ec1725.
Report an issue: GitHub.