{"record":{"id":"9366eee9bcd098d8","repo":"nautechsystems/nautilus_trader","slug":"type-name-raw-value-overflows-u256-while-roundin","errorCode":null,"errorMessage":"{type_name} raw value overflows U256 while rounding half to even","messagePattern":"(.+?) raw value overflows U256 while rounding half to even","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/decode.rs","lineNumber":144,"sourceCode":"    if raw > raw_max {\n        anyhow::bail!(\"{type_name} raw value {raw} exceeds {raw_max_name}={raw_max}\");\n    }\n\n    Ok(())\n}\n\nfn round_u256_half_even(amount: U256, excess: u8, type_name: &str) -> anyhow::Result<U256> {\n    let Some(divisor) = U256::from(10).checked_pow(U256::from(excess)) else {\n        // The divisor exceeds U256::MAX, so every U256 amount is below half a retained unit\n        return Ok(U256::ZERO);\n    };\n    let quotient = amount / divisor;\n    let remainder = amount % divisor;\n    let half = divisor / U256::from(2);\n\n    if remainder > half || (remainder == half && quotient.bit(0)) {\n        quotient.checked_add(U256::from(1)).ok_or_else(|| {\n            anyhow::anyhow!(\"{type_name} raw value overflows U256 while rounding half to even\")\n        })\n    } else {\n        Ok(quotient)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use alloy::primitives::U256;\n    use rstest::rstest;\n\n    use super::*;\n\n    #[rstest]\n    #[case::zero(U256::ZERO, 6, 0, 6)]\n    #[case::one(U256::from(1), 6, 10_000_000_000, 6)]\n    #[case::above_f64_integer_limit(\n        U256::from(9_007_199_254_740_993_u64),","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/decode.rs#L126-L162","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nlet qty = u256_to_price(raw, 60, 18, \"TokenX\")?; // downscale rounds a near-max value up\n// after\nensure!(raw < U256::MAX, \"amount implausibly large for TokenX\");\nlet qty = u256_to_price(raw, 60, 18, \"TokenX\")?;","handlingStrategy":"validation","validationCode":"fn rounds_within_u256(amount: U256, divisor: U256) -> bool {\n    let quotient = amount / divisor;\n    let remainder = amount % divisor;\n    !(quotient == U256::MAX && (remainder * U256::from(2) >= divisor))\n}","typeGuard":null,"tryCatchPattern":"match scale_u256_to_raw_call(...) {\n    Ok(v) => use(v),\n    Err(e) if e.to_string().contains(\"rounding half to even\") => reject_record(e),\n    Err(e) => return Err(e),\n}","preventionTips":["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"],"tags":["overflow","u256","rounding","arithmetic"],"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-14T05:17:10.506Z"}