nautechsystems/nautilus_trader · error

Cumulative spread fill went backwards: acc_fill_sz='{}' < pr

Error message

Cumulative spread fill went backwards: acc_fill_sz='{}' < previous_filled_qty={} (possible stale data after reconnect)

What it means

OKX spread order updates report cumulative filled size (acc_fill_sz). The parser keeps the previously known filled quantity and rejects updates where the new cumulative value is less than the previous one, since that indicates stale/duplicate data (often after a reconnect) rather than a real fill regression.

Source

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

    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={}",
                    msg.acc_fill_sz,
                    prev_qty
                );
                return Ok(None);
            }
        }
    } else {
        anyhow::bail!(

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Verify only one spread-orders subscription is active and reconnect logic doesn't replay old messages
  2. Discard/regenerate order state from a fresh REST snapshot after reconnect instead of trusting interleaved WS updates
  3. If genuinely out-of-order data is expected, catch this error and drop the stale update rather than failing the stream

Example fix

// before
let report = parse_spread_order_fill_report(msg, prev_qty)?; // bails on regression
// after
match parse_spread_order_fill_report(msg, prev_qty) {
    Ok(r) => handle(r),
    Err(e) if e.to_string().contains("went backwards") => tracing::warn!("stale spread update dropped"),
    Err(e) => return Err(e),
}
Defensive patterns

Strategy: try-catch

Validate before calling

if let Some(prev) = previous_filled_qty {
    if let Some(acc) = &msg.acc_fill_sz {
        if acc.parse::<f64>().map_or(true, |v| (v as u64) < prev.raw()) {
            // stale/out-of-order update; drop before parsing
        }
    }
}

Try / catch

match parse_spread_order_fill_report(&msg, prev_qty) {
    Ok(Some(r)) => handle(r),
    Ok(None) => {}
    Err(e) if e.to_string().contains("went backwards") => {
        tracing::warn!("dropping stale spread update: {e}");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: A sprd-orders update arrives with acc_fill_sz lower than the previously tracked filled quantity for the same spread order, typically after a WebSocket reconnect replaying older messages.

Common situations: WS reconnect delivering a delayed/older update out of order; subscribing to the same channel twice; replayed snapshots mixed with live updates.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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