nautechsystems/nautilus_trader · error · anyhow::Error

Failed to parse spread fill_sz='{}': {e}

Error message

Failed to parse spread fill_sz='{}': {e}

What it means

The OKX WebSocket adapter failed to parse the order message's incremental fill size (`fill_sz`) into a Quantity rounded to the spread instrument's size precision while building an OrderFilled report for a spread instrument. This error is thrown because a malformed or unrepresentable fill size cannot produce a valid fill event, and silently dropping it would corrupt order state tracking.

Source

Thrown at crates/adapters/okx/src/websocket/parse.rs:2007

            format!("cancel_source={source}")
        };
        report = report.with_cancel_reason(reason);
    }

    Ok(report)
}

fn parse_spread_order_fill_report(
    msg: &OKXSpreadOrder,
    instrument: &InstrumentAny,
    _account_id: AccountId,
    previous_filled_qty: Option<Quantity>,
    _ts_init: UnixNanos,
) -> anyhow::Result<Option<FillReport>> {
    let size_precision = instrument.size_precision();
    if !msg.fill_sz.is_empty() && msg.fill_sz != "0" {
        parse_quantity(&msg.fill_sz, size_precision).map_err(|e| {
            anyhow::anyhow!("Failed to parse spread fill_sz='{}': {e}", msg.fill_sz)
        })?;
    } else if !msg.acc_fill_sz.is_empty() && msg.acc_fill_sz != "0" {
        let current_filled = parse_quantity(&msg.acc_fill_sz, size_precision).map_err(|e| {
            anyhow::anyhow!(
                "Failed to parse spread acc_fill_sz='{}': {e}",
                msg.acc_fill_sz
            )
        })?;

        if let Some(prev_qty) = previous_filled_qty {
            if current_filled < prev_qty {
                anyhow::bail!(
                    "Cumulative spread fill went backwards: acc_fill_sz='{}' < previous_filled_qty={} \
                     (possible stale data after reconnect)",
                    msg.acc_fill_sz,
                    prev_qty
                );
            }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Refresh the instrument definition (lotSz from OKX spread instruments endpoint) so size_precision matches the exchange's actual precision, then reconnect the WebSocket.
  2. Log the raw msg (channel/arg + data) and inspect fill_sz for non-numeric or over-precise values.
  3. If OKX changed the field format, update parse_quantity / the OkxOrderMsg model in this adapter.
  4. If the value is genuinely invalid from the exchange, treat it as an upstream data issue: skip the fill and resync order state via REST.

Example fix

// before: instrument def with stale lotSz -> size_precision = 0 rejects '0.5'
// after: reload instrument definitions before subscribing
let instrument = await provider.instrument(instrument_id).await?; // fresh lotSz
ws.subscribe_spread_orders(instrument);
Defensive patterns

Strategy: validation

Validate before calling

// Rust: verify fill_sz parses at the instrument's precision before it reaches the stream handler
fn is_valid_fill_sz(fill_sz: &str, precision: u32) -> bool {
    !fill_sz.is_empty() && fill_sz != "0"
        && rust_decimal::Decimal::from_str(fill_sz).map(|d| d.scale() as u32 <= precision).unwrap_or(false)
}

Try / catch

match parse_spread_order_event(msg, instrument, ...) {
    Ok(Some(event)) => handle(event),
    Ok(None) => {}
    Err(e) => { log::warn!("skipping bad spread fill: {e:#}"); resync_order_state(inst_id); }
}

Prevention

When it happens

Trigger: parse_spread_order_event / parse_spread_order_msg receive an OKX 'orders' channel message for a spread (SPRW/SPOT instrument family) where fill_sz is non-empty and not "0", but parse_quantity(fill_sz, size_precision) fails — e.g. fill_sz contains a non-numeric string, is negative, or has more decimals than the instrument's size_precision.

Common situations: OKX pushes an unexpected fill_sz format after an API change; the local spread InstrumentDef has a stale/incorrect lot size (size_precision) that rejects a legitimate fill size like '0.0001'; corrupted or hand-crafted test payloads.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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