nautechsystems/nautilus_trader · error · anyhow::Error

Failed to create price from fill px: {e}

Error message

Failed to create price from fill px: {e}

What it means

Raised in parse_fill_report when Price::from_decimal_dp fails converting fill.px (the trade price) into a domain Price at the instrument's price precision. The Price type uses fixed-point storage, so it rejects negative values, precision above its fixed maximum, and raw-range overflow. This means the venue-reported fill price cannot be represented for this instrument.

Source

Thrown at crates/adapters/hyperliquid/src/http/parse.rs:1186

            fill.sz,
        );
    }

    let trade_id = make_fill_trade_id(
        &fill.hash,
        fill.oid,
        fill.px,
        fill.sz,
        fill.time,
        fill.start_position,
    );
    let order_side = parse_fill_side(&fill.side);

    let price_precision = instrument.price_precision();
    let size_precision = instrument.size_precision();

    let last_px = Price::from_decimal_dp(fill.px, price_precision)
        .map_err(|e| anyhow::anyhow!("Failed to create price from fill px: {e}"))?;
    let last_qty = Quantity::from_decimal_dp(fill.sz.abs(), size_precision)
        .map_err(|e| anyhow::anyhow!("Failed to create quantity from fill sz: {e}"))?;

    let fee_amount = fill.fee;

    let fee_currency = resolve_fee_currency(fill.fee_token.as_str(), fee_amount, instrument)?;
    let commission = Money::from_decimal(fee_amount, fee_currency)
        .map_err(|e| anyhow::anyhow!("Failed to create commission from fee: {e}"))?;

    // Determine liquidity side based on 'crossed' flag
    let liquidity_side = if fill.crossed {
        LiquiditySide::Taker
    } else {
        LiquiditySide::Maker
    };

    let ts_event = UnixNanos::from(fill.time * 1_000_000);
    let report_id = UUID4::new();

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check the fill.px value in the raw response and the instrument's price_precision; refresh instrument definitions if stale
  2. Confirm the fill's coin maps to the correct instrument so the right precision is applied
  3. Round px to instrument precision upstream, or widen the instrument definition's price_precision
  4. Handle per-fill errors so one bad fill doesn't fail the whole fills response

Example fix

// before
let last_px = Price::from_decimal_dp(fill.px, price_precision)
    .map_err(|e| anyhow::anyhow!("Failed to create price from fill px: {e}"))?;
// after
let last_px = Price::from_decimal_dp(fill.px, price_precision)
    .map_err(|e| anyhow::anyhow!("Failed to create price from fill px {}: {e}", fill.px))?;
Defensive patterns

Strategy: try-catch

Validate before calling

# Python: check fill price sanity before requesting fills processing
assert fill_px > 0, "fill price must be positive"

Try / catch

try:
    fills = client.request_fill_reports(...)
except ValueError as e:
    if "fill px" in str(e):
        log.warning("skipping unrepresentable fill: %s", e)
    else:
        raise

Prevention

When it happens

Trigger: Calling fill_reports_from_response (user fills HTTP endpoint) for a fill whose px is negative, has more decimals than price_precision, or whose magnitude overflows PriceRaw during scaling.

Common situations: Fills on newly listed or odd-precision assets whose instrument definition precision is stale; exchange returning anomalous fill prices (e.g. zero-liquidity prints); parsing historical fills after the venue changed tick size.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/da14c628a2505d10. Report an issue: GitHub.