nautechsystems/nautilus_trader · error
effective raw scale should fit in MoneyRaw
Error message
effective raw scale should fit in MoneyRaw
What it means
Money's Display impl (fmt) divides the raw value by the effective raw scale to render the amount. The scale 10^precision is converted into MoneyRaw via try_from, and if the currency precision implies a scale not representable in MoneyRaw the conversion expect panics with this message. Displaying can therefore panic on pathological precision values.
Source
Thrown at crates/model/src/types/money.rs:690
self.as_f64() * rhs
}
}
impl Div<f64> for Money {
type Output = f64;
fn div(self, rhs: f64) -> Self::Output {
self.as_f64() / rhs
}
}
impl Debug for Money {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.currency.precision > crate::types::fixed::MAX_FLOAT_PRECISION {
write!(f, "{}({}, {})", stringify!(Money), self.raw, self.currency)
} else {
let precision = self.currency.precision;
let scale = MoneyRaw::try_from(raw_scale(precision))
.expect("effective raw scale should fit in MoneyRaw");
let currency_scale = MoneyRaw::pow(10, u32::from(precision));
let amount = self.raw / (scale / currency_scale);
if precision == 0 {
write!(f, "{}({}, {})", stringify!(Money), amount, self.currency)
} else {
let sign = if amount < 0 { "-" } else { "" };
let amount_abs = amount.unsigned_abs();
let currency_scale = currency_scale.unsigned_abs();
let whole = amount_abs / currency_scale;
let fraction = amount_abs % currency_scale;
write!(
f,
"{}({sign}{whole}.{fraction:0>width$}, {})",
stringify!(Money),
self.currency,
width = usize::from(precision),
)View on GitHub (pinned to 18893faf8b)
Solutions
- Correct the Currency's precision to a realistic value (typically 0-9 decimal places).
- Validate currency precision when constructing/registering the currency.
- Avoid formatting until the currency definition is fixed; inspect the raw value instead.
Example fix
// before
let cur = Currency::from("XYZ").with_precision(45);
println!("{}", Money::new(dec, cur)); // panics in fmt
// after
let cur = Currency::from("XYZ").with_precision(8); // sane precision
println!("{}", Money::new(dec, cur)); Defensive patterns
Strategy: validation
Validate before calling
if currency.precision > 38 { // 10^38 overflows i128 MoneyRaw
panic!("currency precision {} too large for display", currency.precision);
}
format!("{}", money) Type guard
fn printable(currency: &Currency) -> bool {
u32::from(currency.precision) <= 38 && u64::from(currency.precision) <= u32::MAX.into()
} Prevention
- Validate currency precision (realistic 0-9 decimals) at currency registration time.
- Audit exchange adapters that synthesize Currency definitions from venue metadata.
- Test that Display formatting works for every currency your system registers at startup.
When it happens
Trigger: Formatting (println!, format!, to_string, logging) any Money whose currency precision exceeds what MoneyRaw can represent as 10^precision (roughly precision > 38 for i128 raw, lower in non-high-precision builds).
Common situations: A Currency configured with an invalid/extreme precision (bad asset definition from a config or exchange adapter); debugging output of a mis-constructed Money. Note the code prints raw fallback only when precision > MAX_FLOAT_PRECISION, so extreme-but-below-that precisions still hit the scale conversion.
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
- total PnL overflow
- quantity for {currency} exceeds signed raw bounds
- quantity for {currency} overflowed while increasing raw scal
- Failed to scale continuous-future adjustment to fixed precis
- invalid betting balance impact
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/e4b028427b54e8eb.
Report an issue: GitHub.