nautechsystems/nautilus_trader · error · anyhow::Error

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

Error message

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

What it means

When a spread order message has no incremental fill_sz, the adapter falls back to parsing the cumulative filled size acc_fill_sz with the spread instrument's size precision. This error is thrown when that cumulative value cannot be converted to a Quantity, so no incremental fill can be derived and the fill report must be aborted.

Source

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

    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
                );
            }

            if (current_filled - prev_qty).is_zero() {
                log::debug!(
                    "Skipping duplicate spread fill: acc_fill_sz='{}' unchanged from previous={}",

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Refresh the spread instrument definition so size_precision accommodates the received acc_fill_sz precision.
  2. Inspect the raw message payload to confirm acc_fill_sz is numeric and non-negative.
  3. Resynchronize order/fill state from REST if the WebSocket stream delivered bad or stale data.
  4. Update the adapter's parsing/model code if OKX changed the accFillSz format.
Defensive patterns

Strategy: validation

Validate before calling

// Rust: check acc_fill_sz parses cleanly before processing the update
fn is_valid_acc_fill_sz(acc: &str, precision: u32) -> bool {
    rust_decimal::Decimal::from_str(acc).map(|d| d.is_sign_positive() && d.scale() as u32 <= precision).unwrap_or(false)
}

Try / catch

match parse_spread_order_event(msg, instrument, ...) {
    Ok(v) => handle(v),
    Err(e) => { log::warn!("spread acc_fill_sz error: {e:#}"); schedule_rest_resync(); }
}

Prevention

When it happens

Trigger: parse_spread_order_event / parse_spread_order_msg get a spread order update where fill_sz is empty or "0" and acc_fill_sz is non-empty and not "0", but parse_quantity(acc_fill_sz, size_precision) fails (non-numeric text, negative value, more decimals than size_precision).

Common situations: Exchange sends accFillSz with precision exceeding the locally cached spread instrument's lotSz; a stale instrument definition after OKX changed spread tick/lot sizes; unexpected payload from an undocumented spread channel change.

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