nautechsystems/nautilus_trader · error
Inverted price numerator exceeds U256 range
Error message
Inverted price numerator exceeds U256 range
What it means
In `decode_sqrt_price_x96_to_price_tokens_adjusted`, when the price must be inverted (token0/token1 direction swap) and the decimal difference is non-negative, the numerator `divisor_base * fixed_scalar` is computed with checked multiplication. The library throws this error when that product exceeds the U256 range, i.e. the fixed scalar is too large for the inversion path.
Source
Thrown at crates/model/src/defi/tick_map/sqrt_price_math.rs:395
invert: bool,
) -> anyhow::Result<Price> {
let sqrt_price = U256::from(sqrt_price_x96);
let decimal_diff = i32::from(token0_decimals) - i32::from(token1_decimals);
let token0_scalar = FullMath::pow10(token0_decimals)?;
let token1_scalar = FullMath::pow10(token1_decimals)?;
let decimal_adjustment = if decimal_diff >= 0 {
token0_scalar / token1_scalar
} else {
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)?
}View on GitHub (pinned to 18893faf8b)
Solutions
- Verify token decimals metadata is correct; a wrong decimals field inflates decimal_diff.
- Handle inversion by swapping the numerator/denominator arguments instead of requesting invert with a huge scalar.
- Pre-check `decimal_diff` bounds before calling and clamp the adjustment.
- Compute the scalar in U512 and only narrow after division.
Example fix
// before let price = decode_sqrt_price_x96_to_price_tokens_adjusted(sqrt_price, base_dec, quote_dec, true)?; // after ensure!((base_dec - quote_dec).abs() <= 36, "decimal diff too large for inversion"); let price = decode_sqrt_price_x96_to_price_tokens_adjusted(sqrt_price, base_dec, quote_dec, true)?;
Defensive patterns
Strategy: validation
Validate before calling
fn inversion_safe(decimal_diff: i32) -> bool {
// divisor_base = 2^192; require scalar = 10^decimal_diff to fit alongside it in U256
decimal_diff <= 19
} Try / catch
match decode_sqrt_price_x96_to_price_tokens_adjusted(sqrt_price, base, quote, invert) {
Ok(p) if p.is_zero() => handle_extreme_price(),
Ok(p) => p,
Err(e) if e.to_string().contains("numerator exceeds U256") => recompute_without_inversion(),
Err(e) => return Err(e),
} Prevention
- Verify token decimals from a trusted source before pool math
- Prefer swapping numerator/denominator over requesting inversion with large decimal diffs
- Clamp or reject pools with extreme decimal asymmetry at pool-registration time
When it happens
Trigger: Calling the decode/spot-price function with `invert=true` and a large `decimal_diff` whose adjustment scalar, multiplied by 2^192, overflows U256 — e.g. very asymmetric token decimals combined with inversion.
Common situations: Pools pairing tokens with wildly different decimals (e.g. 18 vs 0-2 decimals) where quote-direction inversion is requested; misreported token decimals inflating `decimal_diff`.
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 denominator 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/692550a776a46cf1.
Report an issue: GitHub.