nautechsystems/nautilus_trader · error

raw wei value exceeds 128-bit range

Error message

raw wei value exceeds 128-bit range

What it means

Money::from_wei accepts a raw wei value as U256 but the internal fixed-precision representation only stores values up to i128. The U256-to-u128 TryInto conversion is unwrapped with expect, so any wei amount larger than u128::MAX panics with this message (a follow-up assert also rejects values above i128::MAX). The library throws it because amounts exceeding the native integer width cannot be represented losslessly in Money.

Source

Thrown at crates/model/src/defi/types/money.rs:62

    /// # Panics
    ///
    /// Panics if `currency.precision` is not 18, or if the raw wei value exceeds the
    /// signed 128-bit range.
    pub fn from_wei<U>(raw_wei: U, currency: Currency) -> Self
    where
        U: Into<U256>,
    {
        assert!(
            currency.precision == 18,
            "`from_wei` requires a currency with precision 18, was {} for {}",
            currency.precision,
            currency.code,
        );

        let raw_u256: U256 = raw_wei.into();
        let raw_u128: u128 = raw_u256
            .try_into()
            .expect("raw wei value exceeds 128-bit range");

        assert!(
            raw_u128 <= i128::MAX as u128,
            "raw wei value exceeds signed 128-bit range"
        );

        let raw_i128: i128 = raw_u128 as i128;
        Self::from_raw(raw_i128, currency)
    }

    /// Converts this [`Money`] instance to raw wei value.
    ///
    /// # Panics
    ///
    /// Panics if `self.currency.precision` is not 18 or `self.raw` is negative.
    /// For other precisions convert to precision 18 first.
    #[must_use]
    pub fn to_wei(&self) -> U256 {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check the raw value before conversion: only call from_wei when raw_wei <= U256::from(u128::MAX) (and <= i128::MAX if sign matters).
  2. Reject or clamp the value at the data-ingestion layer; skip the token/instrument or log a warning instead of converting.
  3. Verify the ABI/log decoding that produced the U256 — a decode bug can yield spuriously large values.
  4. If such magnitudes are legitimate, request upstream support for a big-number (U256) representation instead of working around it.

Example fix

// before
let money = Money::from_wei(raw_wei_u256, currency); // panics if raw > u128::MAX
// after
let money = if raw_wei_u256 <= U256::from(u128::MAX) {
    Money::from_wei(raw_wei_u256, currency)
} else {
    return Err("wei amount exceeds 128-bit range".to_string());
};
Defensive patterns

Strategy: validation

Validate before calling

use alloy_primitives::U256;
fn wei_fits_u128(raw_wei: U256) -> bool {
    raw_wei <= U256::from(i128::MAX)
}

Type guard

fn fits_i128(raw: U256) -> Option<u128> {
    let r: u128 = raw.try_into().ok()?;
    (r <= i128::MAX as u128).then_some(r)
}

Prevention

When it happens

Trigger: Calling Money::from_wei (or its Python/FFI wrapper money_from_wei) with a raw wei value > u128::MAX (≈3.4e38), e.g. huge token supplies or overflowed aggregation results, or passing a negative/wrapped U256 produced by a downstream ABI decode bug.

Common situations: Indexing a token with an enormous total supply (or high decimals) whose raw wei amounts overflow 128 bits; feeding raw on-chain values from a mis-decoded log; upgrading a data pipeline to aggregate balances across many wallets so the sum overflows.

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


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/4fb0f6ef1bc41748. Report an issue: GitHub.