{"record":{"id":"a38df7ad4d7bcff7","repo":"nautechsystems/nautilus_trader","slug":"decimal-exponent-exponent-exceeds-u8-range","errorCode":null,"errorMessage":"Decimal exponent {exponent} exceeds u8 range","messagePattern":"Decimal exponent (.+?) exceeds u8 range","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/model/src/defi/data/swap_trade_info.rs","lineNumber":418,"sourceCode":"        }\n\n        // Determine base and quote amounts/decimals based on inversion\n        let (quote_amount, base_amount, quote_decimals, base_decimals) = if self.is_inverted {\n            // inverted: token0=quote, token1=base\n            (amount0, amount1, self.token0.decimals, self.token1.decimals)\n        } else {\n            // not inverted: token0=base, token1=quote\n            (amount1, amount0, self.token1.decimals, self.token0.decimals)\n        };\n\n        FullMath::check_decimal_exponent(base_decimals)?;\n        FullMath::check_decimal_exponent(quote_decimals)?;\n\n        let exponent =\n            i16::from(base_decimals) + i16::from(FIXED_PRECISION) - i16::from(quote_decimals);\n        let price_raw_u256 = if exponent >= 0 {\n            let exponent = u8::try_from(exponent)\n                .map_err(|_| anyhow::anyhow!(\"Decimal exponent {exponent} exceeds u8 range\"))?;\n            let primary_exponent = exponent.min(DECIMAL_EXPONENT_MAX);\n            let secondary_exponent = exponent - primary_exponent;\n            let primary_scalar = FullMath::pow10(primary_exponent)?;\n            let secondary_scalar = FullMath::pow10(secondary_exponent)?;\n            FullMath::mul_div_scaled(\n                quote_amount,\n                U256::from(1),\n                base_amount,\n                &[primary_scalar, secondary_scalar],\n            )?\n        } else {\n            let divisor_exponent = u8::try_from(exponent.unsigned_abs())\n                .map_err(|_| anyhow::anyhow!(\"Decimal exponent {exponent} exceeds u8 range\"))?;\n            let divisor = FullMath::pow10(divisor_exponent)?;\n            (quote_amount / base_amount) / divisor\n        };\n\n        price_from_u256(price_raw_u256)","sourceCodeStart":400,"sourceCodeEnd":436,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/model/src/defi/data/swap_trade_info.rs#L400-L436","documentation":"`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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nlet price = trade_info.execution_price(base_decimals, quote_decimals)?; // panics pipeline on bad decimals\n// after\nif base_decimals > 36 || quote_decimals > 36 {\n    return Ok(None); // skip implausible token metadata\n}\nlet price = trade_info.execution_price(base_decimals, quote_decimals).ok();","handlingStrategy":"validation","validationCode":"fn exponent_ok(base_decimals: u8, quote_decimals: u8, fixed_precision: u32) -> bool {\n    let e = i64::from(base_decimals) + i64::from(fixed_precision) - i64::from(quote_decimals);\n    (0..=255).contains(&e)\n}","typeGuard":null,"tryCatchPattern":"match quote.calculate_trade_info(&token0, &token1) {\n    Ok(()) => { /* use trade info */ }\n    Err(e) if e.to_string().contains(\"exceeds u8 range\") => eprintln!(\"skipping pair: bad decimals: {e}\"),\n    Err(e) => return Err(e),\n}","preventionTips":["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"],"tags":["defi","decimal-exponent","overflow"],"backgroundTag":"value-out-of-range","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}