nautechsystems/nautilus_trader · error
{type_name} raw value overflows U256 while rounding half to
Error message
{type_name} raw value overflows U256 while rounding half to even What it means
Raised by round_u256_half_even when the round-up branch (remainder > half, or tie with odd quotient) calls quotient.checked_add(1) and the quotient is U256::MAX, so incrementing by one would overflow. It occurs during downscaling (decimals > fixed_precision) of a U256 raw value to fewer decimals. The library throws it instead of silently wrapping.
Source
Thrown at crates/adapters/blockchain/src/decode.rs:144
if raw > raw_max {
anyhow::bail!("{type_name} raw value {raw} exceeds {raw_max_name}={raw_max}");
}
Ok(())
}
fn round_u256_half_even(amount: U256, excess: u8, type_name: &str) -> anyhow::Result<U256> {
let Some(divisor) = U256::from(10).checked_pow(U256::from(excess)) else {
// The divisor exceeds U256::MAX, so every U256 amount is below half a retained unit
return Ok(U256::ZERO);
};
let quotient = amount / divisor;
let remainder = amount % divisor;
let half = divisor / U256::from(2);
if remainder > half || (remainder == half && quotient.bit(0)) {
quotient.checked_add(U256::from(1)).ok_or_else(|| {
anyhow::anyhow!("{type_name} raw value overflows U256 while rounding half to even")
})
} else {
Ok(quotient)
}
}
#[cfg(test)]
mod tests {
use alloy::primitives::U256;
use rstest::rstest;
use super::*;
#[rstest]
#[case::zero(U256::ZERO, 6, 0, 6)]
#[case::one(U256::from(1), 6, 10_000_000_000, 6)]
#[case::above_f64_integer_limit(
U256::from(9_007_199_254_740_993_u64),View on GitHub (pinned to 18893faf8b)
Solutions
- Check the input amount: quotient near U256::MAX indicates a bad or adversarial value; reject the record before calling the conversion
- Correct the token decimals metadata so the amount is interpreted as a realistic magnitude
- Clamp or pre-validate the amount against a sane upper bound (e.g., total supply) before conversion
- If legitimate huge values are required, this code path cannot support them with U256; use a wider integer representation
Example fix
// before let qty = u256_to_price(raw, 60, 18, "TokenX")?; // downscale rounds a near-max value up // after ensure!(raw < U256::MAX, "amount implausibly large for TokenX"); let qty = u256_to_price(raw, 60, 18, "TokenX")?;
Defensive patterns
Strategy: validation
Validate before calling
fn rounds_within_u256(amount: U256, divisor: U256) -> bool {
let quotient = amount / divisor;
let remainder = amount % divisor;
!(quotient == U256::MAX && (remainder * U256::from(2) >= divisor))
} Try / catch
match scale_u256_to_raw_call(...) {
Ok(v) => use(v),
Err(e) if e.to_string().contains("rounding half to even") => reject_record(e),
Err(e) => return Err(e),
} Prevention
- Reject inputs whose magnitude approaches 2^256 before conversion
- Verify decimals metadata so values are interpreted at realistic scale
- Treat near-max U256 event payloads as adversarial and skip them
- Unit-test conversions at U256 boundary values
When it happens
Trigger: Calling scale_u256_to_raw with decimals > fixed_precision and an amount whose scaled quotient rounds up to a value exceeding U256::MAX, i.e. quotient == U256::MAX with a positive rounding adjustment.
Common situations: Adversarial or malformed event payloads carrying values near 2^256; misconfigured decimals metadata causing a downscale that still produces a max-size quotient; fuzz/test inputs at U256 bounds.
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
- WETH balance overflow for included transaction {tx_hash} at
- {type_name} amount {amount} overflows U256 while scaling fro
- Order amount scaling overflow
- Order amount overflow scaling quantity to raw token units
- Executed amount scaling overflow
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/9366eee9bcd098d8.
Report an issue: GitHub.