nautechsystems/nautilus_trader · error

decimal `{value}` does not fit in i64

Error message

decimal `{value}` does not fit in i64

What it means

The adapter truncates a Decimal order quantity/price to an i64 (venue expects integer raw values) via trunc().to_i64(). If the decimal's integer part exceeds the i64 range it cannot be represented and this error is returned instead of silently corrupting the order.

Source

Thrown at crates/adapters/lighter/src/websocket/dispatch.rs:2134

/// representation, given the instrument's price precision.
pub(crate) fn price_to_ticks(price: &Price, decimals: u8) -> anyhow::Result<u32> {
    let scaled = price.as_decimal() * Decimal::from(10_i64.pow(u32::from(decimals)));
    let value = decimal_trunc_to_i64(scaled)
        .with_context(|| format!("price `{price}` overflows i64 at precision {decimals}"))?;
    u32::try_from(value).with_context(|| {
        format!("price `{price}` overflows u32 (Lighter limit) at precision {decimals}")
    })
}

/// Truncate a [`Decimal`] toward zero and convert to `i64`, returning an
/// error if the truncated value does not fit. Avoids the
/// `decimal.to_string().split('.').parse()` round-trip the previous
/// implementations used; runs on every exec submit and modify.
fn decimal_trunc_to_i64(value: Decimal) -> anyhow::Result<i64> {
    value
        .trunc()
        .to_i64()
        .ok_or_else(|| anyhow::anyhow!("decimal `{value}` does not fit in i64"))
}

/// Derive a worst-acceptable price (in venue ticks) for `MARKET` /
/// `STOP_MARKET` / `MARKET_IF_TOUCHED` orders. Buys widen `base` upward,
/// sells downward, by `slippage_bps`; the result rounds conservatively at
/// `price_precision` so the venue cap never under-shoots the budget.
pub(crate) fn derive_market_order_price_ticks(
    base: Decimal,
    is_buy: bool,
    price_precision: u8,
    slippage_bps: u32,
) -> anyhow::Result<u32> {
    let slippage = Decimal::new(i64::from(slippage_bps), 4);
    let widened = if is_buy {
        base * (Decimal::ONE + slippage)
    } else {
        base * (Decimal::ONE - slippage)
    };

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Fix the source of the oversized Decimal (check sizing math and units)
  2. Clamp or validate the value against i64 bounds before submitting
  3. Verify instrument-specific price/size multipliers and precision are correct

Example fix

// before
let qty = Decimal::from_str("1e20")?; // overflows i64
// after
let qty = Decimal::from_str("1e20")?;
anyhow::ensure!(qty <= Decimal::from(i64::MAX), "qty too large");
Defensive patterns

Strategy: validation

Validate before calling

anyhow::ensure!(value >= Decimal::from(i64::MIN) && value <= Decimal::from(i64::MAX), "value not representable as i64");

Type guard

fn fits_i64(value: Decimal) -> bool {
    value >= Decimal::from(i64::MIN) && value <= Decimal::from(i64::MAX)
}

Try / catch

match decimal_trunc_to_i64(qty) {
    Ok(v) => submit(v),
    Err(e) => { log::error!("order value overflow: {e}"); /* halt or recompute size */ }
}

Prevention

When it happens

Trigger: Any exec submit or modify where the Decimal value (after truncation) is greater than i64::MAX or less than i64::MIN — typically a huge quantity or price caused by bad sizing math or a wrong instrument multiplier.

Common situations: Position sizing bug multiplying by a large factor; fetching price/size from the wrong instrument; uninitialized/default order parameters; decimal points misplaced when constructing amounts.

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/4009fa756d1b287a. Report an issue: GitHub.