nautechsystems/nautilus_trader · error
Decimal exponent {exponent} exceeds U256 range
Error message
Decimal exponent {exponent} exceeds U256 range What it means
`pow10` computes 10^exponent as a U256 after validating the exponent against DECIMAL_EXPONENT_MAX. The library throws this error when `checked_pow` overflows U256 — a defensive backstop for exponents that pass the max check but still cannot fit 10^exponent into 256 bits.
Source
Thrown at crates/model/src/defi/tick_map/full_math.rs:153
remainder = remainder.mul_mod(scale, denominator);
}
Ok(quotient)
}
pub(crate) fn check_decimal_exponent(exponent: u8) -> anyhow::Result<()> {
anyhow::ensure!(
exponent <= DECIMAL_EXPONENT_MAX,
"Decimal exponent {exponent} exceeds supported maximum {DECIMAL_EXPONENT_MAX}"
);
Ok(())
}
pub(crate) fn pow10(exponent: u8) -> anyhow::Result<U256> {
Self::check_decimal_exponent(exponent)?;
U256::from(10)
.checked_pow(U256::from(exponent))
.ok_or_else(|| anyhow::anyhow!("Decimal exponent {exponent} exceeds U256 range"))
}
/// Calculates ceil(a×b÷denominator) with full precision
/// Returns `Ok` with the rounded result or an error when rounding cannot be performed safely.
///
/// # Errors
///
/// Returns error if `denominator` is zero or the rounded result would overflow `U256`.
pub fn mul_div_rounding_up(a: U256, b: U256, denominator: U256) -> anyhow::Result<U256> {
let result = Self::mul_div(a, b, denominator)?;
// Check if there's a remainder
if a.mul_mod(b, denominator).is_zero() {
Ok(result)
} else if result == U256::MAX {
anyhow::bail!("Result would overflow 256 bits")
} else {
Ok(result + U256::from(1))View on GitHub (pinned to 18893faf8b)
Solutions
- Validate the exponent before calling: `ensure!(exponent <= DECIMAL_EXPONENT_MAX)` and that DECIMAL_EXPONENT_MAX < 79.
- Fix the source of the bad exponent (token metadata decoding, config parsing).
- Use U512 for intermediate powers if larger exponents are genuinely required.
Example fix
// before
let pow = pow10(raw_exponent)?;
// after
ensure!(raw_exponent <= DECIMAL_EXPONENT_MAX, "bad exponent {raw_exponent}");
let pow = pow10(raw_exponent)?; Defensive patterns
Strategy: validation
Validate before calling
fn safe_pow10(exponent: u8) -> Option<U256> {
(exponent < 79).then(|| U256::from(10).checked_pow(U256::from(exponent))).flatten()
} Type guard
fn exponent_fits_u256(e: u8) -> bool { e < 79 } Try / catch
match pow10(exponent) {
Ok(v) => v,
Err(e) if e.to_string().contains("U256 range") => {
log::error!("exponent {exponent} overflows U256 — check metadata source");
return Err(e);
}
Err(e) => return Err(e),
} Prevention
- Always route exponents through check_decimal_exponent before pow10
- Validate decimals at the source (token list / ABI decode) instead of deep in math
- Treat u8::MAX or all-ones values from decoders as corruption, not valid exponents
When it happens
Trigger: Calling `pow10` with an exponent large enough that 10^exponent >= 2^256 (exponent >= ~78) — either above DECIMAL_EXPONENT_MAX if that constant allows it, or via a path that bypassed `check_decimal_exponent`.
Common situations: Corrupt decimals metadata (e.g. u8::MAX from a failed decode), or code paths passing raw exponents from external data without prior validation.
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
- Scaled result exceeds 256-bit range
- Decimal exponent {exponent} exceeds supported maximum {DECIM
- Inverted price numerator exceeds U256 range
- Inverted price denominator exceeds U256 range
- Result would overflow 256 bits
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/590db6b02dcbc970.
Report an issue: GitHub.