nautechsystems/nautilus_trader · error
Decimal exponent {exponent} exceeds u8 range
Error message
Decimal exponent {exponent} exceeds u8 range What it means
`SwapTradeInfo::execution_price` computes a raw U256 price as `quote_amount * 10^(base_decimals + FIXED_PRECISION - quote_decimals) / base_amount`. When token decimals make that exponent exceed what fits in a `u8` (i.e. > 255 or negative handling), the `u8::try_from` conversion fails and this error is thrown. It guards against absurd decimal configurations that cannot be represented in the fixed-point scaling used.
Source
Thrown at crates/model/src/defi/data/swap_trade_info.rs:418
}
// Determine base and quote amounts/decimals based on inversion
let (quote_amount, base_amount, quote_decimals, base_decimals) = if self.is_inverted {
// inverted: token0=quote, token1=base
(amount0, amount1, self.token0.decimals, self.token1.decimals)
} else {
// not inverted: token0=base, token1=quote
(amount1, amount0, self.token1.decimals, self.token0.decimals)
};
FullMath::check_decimal_exponent(base_decimals)?;
FullMath::check_decimal_exponent(quote_decimals)?;
let exponent =
i16::from(base_decimals) + i16::from(FIXED_PRECISION) - i16::from(quote_decimals);
let price_raw_u256 = if exponent >= 0 {
let exponent = u8::try_from(exponent)
.map_err(|_| anyhow::anyhow!("Decimal exponent {exponent} exceeds u8 range"))?;
let primary_exponent = exponent.min(DECIMAL_EXPONENT_MAX);
let secondary_exponent = exponent - primary_exponent;
let primary_scalar = FullMath::pow10(primary_exponent)?;
let secondary_scalar = FullMath::pow10(secondary_exponent)?;
FullMath::mul_div_scaled(
quote_amount,
U256::from(1),
base_amount,
&[primary_scalar, secondary_scalar],
)?
} else {
let divisor_exponent = u8::try_from(exponent.unsigned_abs())
.map_err(|_| anyhow::anyhow!("Decimal exponent {exponent} exceeds u8 range"))?;
let divisor = FullMath::pow10(divisor_exponent)?;
(quote_amount / base_amount) / divisor
};
price_from_u256(price_raw_u256)View on GitHub (pinned to 18893faf8b)
Solutions
- Check token decimal metadata (base_decimals, quote_decimals) for correctness at data-ingestion time; reject values > ~38 (realistic ERC-20 range).
- Swap base/quote assignment if tokens were mislabeled.
- Sanitize/validate `FIXED_PRECISION` usage with your token pair before calling; skip the pair if exponent is out of range.
- Handle the anyhow error at the call site and skip the event rather than aborting replay.
Example fix
// before
let price = trade_info.execution_price(base_decimals, quote_decimals)?; // panics pipeline on bad decimals
// after
if base_decimals > 36 || quote_decimals > 36 {
return Ok(None); // skip implausible token metadata
}
let price = trade_info.execution_price(base_decimals, quote_decimals).ok(); Defensive patterns
Strategy: validation
Validate before calling
fn exponent_ok(base_decimals: u8, quote_decimals: u8, fixed_precision: u32) -> bool {
let e = i64::from(base_decimals) + i64::from(fixed_precision) - i64::from(quote_decimals);
(0..=255).contains(&e)
} Try / catch
match quote.calculate_trade_info(&token0, &token1) {
Ok(()) => { /* use trade info */ }
Err(e) if e.to_string().contains("exceeds u8 range") => eprintln!("skipping pair: bad decimals: {e}"),
Err(e) => return Err(e),
} Prevention
- Validate token decimals against realistic ranges (0-36) when ingesting token metadata
- Never trust on-chain-reported decimals blindly; cross-check known token lists
- Log and skip malformed pairs in bulk replay instead of failing the whole run
When it happens
Trigger: Calling `execution_price` (directly or via `SwapTradeInfo` construction / `calculate_trade_info`) with token decimals such that `base_decimals + FIXED_PRECISION - quote_decimals > 255` (positive branch).
Common situations: Malformed or adversarial token metadata from on-chain data where `base_decimals` is huge or misparsed; mixing up which token is base vs quote so decimals arithmetic explodes.
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
- Liquidity {liquidity} exceeds i128::MAX
- Liquidity {} exceeds i128::MAX
- Inverted price numerator exceeds U512 range
- Inverted price exceeds U256 range
- Price overflow: {price_raw} exceeds maximum valid raw price
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/a38df7ad4d7bcff7.
Report an issue: GitHub.