nautechsystems/nautilus_trader · error
Failed to convert Decimal to f64
Error message
Failed to convert Decimal to f64
What it means
Position adjustments carry an optional quantity_change as a Decimal; apply_adjustment_state converts it to f64 to update signed_qty and panics if the Decimal cannot be represented (e.g. beyond f64 range). Conversion to f64 fails only for extreme magnitudes since Decimal supports far wider ranges.
Source
Thrown at crates/model/src/position.rs:672
///
/// # Panics
///
/// Panics if the adjustment's `quantity_change` cannot be converted to f64.
pub fn apply_adjustment(&mut self, adjustment: PositionAdjusted) {
self.apply_adjustment_state(adjustment, true);
}
fn apply_adjustment_state(&mut self, adjustment: PositionAdjusted, record_replay: bool) {
if record_replay {
self.replay_events
.push(PositionReplayEvent::Adjusted(adjustment));
}
// Apply quantity change if present
if let Some(quantity_change) = adjustment.quantity_change {
self.signed_qty += quantity_change
.to_f64()
.expect("Failed to convert Decimal to f64");
self.quantity = Quantity::new(self.signed_qty.abs(), self.size_precision);
if self.quantity > self.peak_qty {
self.peak_qty = self.quantity;
}
}
// Apply PnL change if present
if let Some(pnl_change) = adjustment.pnl_change {
self.realized_pnl = Some(match self.realized_pnl {
Some(current) => current + pnl_change,
None => pnl_change,
});
}
// Update position state based on quantity (source of truth for zero check)
// This handles floating-point precision edge casesView on GitHub (pinned to 18893faf8b)
Solutions
- Sanity-check adjustment.quantity_change magnitude before applying (must be within f64 range, realistically within the instrument's size limits)
- Construct quantity_change from a proper Quantity/domain type rather than an arbitrary Decimal
- Use try_from-style conversion with explicit error handling in custom adjustment code instead of expect
Example fix
// before
self.signed_qty += quantity_change.to_f64().expect("Failed to convert Decimal to f64");
// after
let delta = quantity_change.to_f64().filter(|v| v.is_finite()).ok_or_else(|| anyhow::anyhow!("quantity_change out of range"))?;
self.signed_qty += delta; Defensive patterns
Strategy: validation
Validate before calling
// Rust: before apply_adjustment
let q = adjustment.quantity_change.map(|d| d.to_f64());
if let Some(Some(v)) = q { assert!(v.is_finite() && v.abs() < 1e15, "adjustment out of range"); } Type guard
fn valid_qty_change(d: &Decimal) -> Option<f64> { d.to_f64().filter(|v| v.is_finite()) } Prevention
- Build quantity_change from domain Quantity types, not arbitrary Decimals
- Bound-check adjustments against instrument size limits before applying
- Validate adjustment data coming from external reconciliation feeds
When it happens
Trigger: Applying a PositionAdjustment (via apply_adjustment, purge_events_for_order, rebuild_from_replay, or apply_base_commission_adjustment) whose quantity_change is too large for f64 — astronomically large position sizes/quantities.
Common situations: Unit bugs creating adjustments with raw/unsealed Decimal values (e.g. passing raw scaled integers as quantity_change); corrupted adjustment data from external reconciliation; wrong scale/precision when constructing the 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
- {e}
- List of Positions is empty
- Decimal average price must parse as f64
- Invalid bid price for OrderBook::filtered_view
- Invalid bid quantity for OrderBook::filtered_view
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/b269551e4d5c58af.
Report an issue: GitHub.