nautechsystems/nautilus_trader · error

Cannot determine fill quantity: fill_sz='{}' and acc_fill_sz

Error message

Cannot determine fill quantity: fill_sz='{}' and acc_fill_sz is None

What it means

This variant fires when fill_sz has a value but acc_fill_sz is None. OKX normally sends both on fills; acc_fill_sz alone lets the parser use the cumulative total, and fill_sz alone is insufficient because the parser can't validate monotonicity against previous fills.

Source

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

                let incremental = current_filled - prev_qty;
                if incremental.is_zero() {
                    log::debug!(
                        "Skipping duplicate fill: acc_fill_sz='{acc_fill_sz}' unchanged from previous={prev_qty}"
                    );
                    return Ok(None);
                }
                incremental
            } else {
                // First fill, use accumulated as incremental
                current_filled
            }
        } else {
            anyhow::bail!(
                "Cannot determine fill quantity: fill_sz is empty/zero and acc_fill_sz is empty/zero"
            );
        }
    } else {
        anyhow::bail!(
            "Cannot determine fill quantity: fill_sz='{}' and acc_fill_sz is None",
            msg.fill_sz
        );
    };

    let fee_str = msg
        .fee
        .as_deref()
        .filter(|fee| !fee.trim().is_empty())
        .ok_or_else(|| anyhow::anyhow!("missing fee for fill report inst_id={}", msg.inst_id))?;
    let fee_dec = Decimal::from_str(fee_str)
        .map_err(|e| anyhow::anyhow!("Failed to parse fee '{fee_str}': {e}"))?;

    let fee_currency = parse_fee_currency(msg.fee_ccy.as_str(), fee_dec, || {
        format!("fill report for inst_id={}", msg.inst_id)
    });

    // OKX sends fees as negative numbers (e.g., "-2.5" for a $2.5 charge), parse_fee negates to positive

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Verify the OKX orders channel payload includes acc_fill_sz and update any message-model/serde definitions that drop it
  2. If only incremental fill_sz is available, fall back to using fill_sz directly as the incremental quantity
  3. Check for field-name/serde renames (camelCase vs snake_case) after upgrading the adapter

Example fix

// before
struct OKXOrderMsg { fill_sz: Option<String> } // acc_fill_sz dropped
// after
struct OKXOrderMsg { fill_sz: Option<String>, acc_fill_sz: Option<String> }
Defensive patterns

Strategy: type-guard

Validate before calling

if msg.acc_fill_sz.is_none() {
    tracing::warn!("orders update missing acc_fill_sz; check API schema");
    return Ok(None);
}

Type guard

fn has_cumulative_fill(msg: &OKXOrderMsg) -> bool { msg.acc_fill_sz.is_some() }

Try / catch

if !has_cumulative_fill(&msg) { /* fallback: use fill_sz incrementally or skip */ }

Prevention

When it happens

Trigger: An orders-channel update carrying fill_sz but omitting acc_fill_sz entirely — typically an OKX API shape change, a different channel variant, or a hand-built message.

Common situations: OKX API version updates changing required fields; proxying messages through an intermediary that strips fields; incomplete test fixtures.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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