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
- Refresh the instrument definition (lotSz from OKX spread instruments endpoint) so size_precision matches the exchange's actual precision, then reconnect the WebSocket.
- Log the raw msg (channel/arg + data) and inspect fill_sz for non-numeric or over-precise values.
- If OKX changed the field format, update parse_quantity / the OkxOrderMsg model in this adapter.
- 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
- Reload instrument definitions (lotSz/size_precision) before each WebSocket session.
- Monitor adapter logs for parse failures as an early sign of OKX API schema drift.
- Keep the OKX adapter version aligned with the API version in use.
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.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Failed to parse spread acc_fill_sz='{}': {e}
- Unsupported algo order type: {:?}
- Missing sz for algo order {}
- Cannot determine spread fill quantity: fill_sz='{}' and acc_
- Cannot determine fill quantity: fill_sz is empty/zero and ac
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/4a704cfbd59e8716.
Report an issue: GitHub.