nautechsystems/nautilus_trader · error · anyhow::Error

Failed to convert quantity to u64

Error message

Failed to convert quantity to u64

What it means

quantize_quantity rounds an order size to step_base_quantums and converts the result to u64 for the proto Order. The error fires when the quantized Decimal cannot be represented as u64 — typically a negative size or a size so large it overflows u64::MAX.

Source

Thrown at crates/adapters/dydx/src/grpc/order.rs:159

    ///
    /// Returns an error if conversion fails.
    pub fn quantize_quantity(&self, quantity: Decimal) -> Result<u64, anyhow::Error> {
        // When atomic_resolution is negative, we multiply by 10^|atomic_resolution|
        // When atomic_resolution is positive, we divide by 10^atomic_resolution
        let factor = if self.atomic_resolution < 0 {
            Decimal::from(10_i64.pow(self.atomic_resolution.unsigned_abs()))
        } else {
            Decimal::new(1, self.atomic_resolution.unsigned_abs())
        };

        let raw_quantums = quantity * factor;
        let step_base_quantums = Decimal::from(self.step_base_quantums);
        let quantums = Self::quantize(&raw_quantums, &step_base_quantums);
        let result = quantums.max(step_base_quantums);

        result
            .to_u64()
            .ok_or_else(|| anyhow::anyhow!("Failed to convert quantity to u64"))
    }

    /// A `round`-like function that quantizes a `value` to the `fraction`.
    fn quantize(value: &Decimal, fraction: &Decimal) -> Decimal {
        (value / fraction).round() * fraction
    }

    /// Compute worst-case subticks for a market order using oracle price + slippage.
    ///
    /// # Errors
    ///
    /// Returns an error if oracle price is not available or conversion fails.
    pub fn market_order_subticks(&self, side: OrderSide) -> Result<u64, anyhow::Error> {
        let oracle = self
            .oracle_price
            .ok_or_else(|| anyhow::anyhow!("Oracle price required for market orders"))?;
        let worst_price = match side {
            OrderSide::Buy => oracle * (Decimal::ONE + DEFAULT_MARKET_ORDER_SLIPPAGE),

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Assert quantity > 0 before building the order
  2. Check that step_base_quantums for the market matches the dYdX market configuration
  3. Verify the size units: ensure you pass size in the base currency the adapter expects
  4. Clamp or reject oversized sizes upstream before calling the builder

Example fix

// before
let order = OrderBuilder::new(params).size(size)...build()?;
// after
anyhow::ensure!(size > Decimal::ZERO, "order size must be positive");
anyhow::ensure!(size < Decimal::from(u64::MAX), "order size too large");
let order = OrderBuilder::new(params).size(size)...build()?;
Defensive patterns

Strategy: validation

Validate before calling

anyhow::ensure!(size.is_sign_positive(), "size must be positive");
anyhow::ensure!(size <= Decimal::from(u64::MAX), "size exceeds u64 range");

Type guard

fn is_valid_order_size(d: &Decimal) -> bool {
    d.is_sign_positive() && d <= Decimal::from(u64::MAX)
}

Prevention

When it happens

Trigger: Calling quantize_quantity (directly or via OrderBuilder::build) with a negative quantity, a quantity larger than u64::MAX / step_base_quantums, or a market whose step_base_quantums is misconfigured so quantums.max(step_base_quantums) is unrepresentable.

Common situations: Sizing logic that can produce negative sizes (e.g. closing more than a position holds); wrong unit scaling of size (contracts vs base currency); corrupted or wrong market step_base_quantums; test/strategy code passing raw floats converted badly to Decimal.

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