{"record":{"id":"cc4495df140418a2","repo":"nautechsystems/nautilus_trader","slug":"cannot-determine-spread-fill-quantity-fill-sz","errorCode":null,"errorMessage":"Cannot determine spread fill quantity: fill_sz='{}' and acc_fill_sz='{}'","messagePattern":"Cannot determine spread fill quantity: fill_sz='(.+?)' and acc_fill_sz='(.+?)'","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/okx/src/websocket/parse.rs","lineNumber":2037,"sourceCode":"                anyhow::bail!(\n                    \"Cumulative spread fill went backwards: acc_fill_sz='{}' < previous_filled_qty={} \\\n                     (possible stale data after reconnect)\",\n                    msg.acc_fill_sz,\n                    prev_qty\n                );\n            }\n\n            if (current_filled - prev_qty).is_zero() {\n                log::debug!(\n                    \"Skipping duplicate spread fill: acc_fill_sz='{}' unchanged from previous={}\",\n                    msg.acc_fill_sz,\n                    prev_qty\n                );\n                return Ok(None);\n            }\n        }\n    } else {\n        anyhow::bail!(\n            \"Cannot determine spread fill quantity: fill_sz='{}' and acc_fill_sz='{}'\",\n            msg.fill_sz,\n            msg.acc_fill_sz\n        );\n    }\n\n    anyhow::bail!(\n        \"missing fee for spread fill report sprd_id={}; OKX sprd-orders updates omit fee\",\n        msg.sprd_id\n    )\n}\n\n/// Parses an OKX order message into a Nautilus fill report.\n///\n/// # Errors\n///\n/// Returns an error if order quantities, prices, or fees cannot be parsed.\npub fn parse_fill_report(","sourceCodeStart":2019,"sourceCodeEnd":2055,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/okx/src/websocket/parse.rs#L2019-L2055","documentation":"To compute a spread fill quantity the update must carry either the incremental fill_sz or the cumulative acc_fill_sz. When both are missing/empty the parser cannot determine how much was filled and bails.","triggerScenarios":"A sprd-orders update arrives where fill_sz is empty/zero-valued and acc_fill_sz is None/empty — e.g. a pure status change (canceled, state update) being routed through the fill-report parser.","commonSituations":"OKX pushing non-fill spread order updates that the event router mistakenly treats as fills; API changes removing fields; partially populated test fixtures.","solutions":["Check the raw message: route only sprd-orders updates with a fill state through parse_spread_order_fill_report","Return a non-fill event (status update) when both size fields are absent instead of treating it as an error","Verify against current OKX sprd-orders docs whether field semantics changed"],"exampleFix":"// before\nanyhow::bail!(\"Cannot determine spread fill quantity: ...\");\n// after\nif msg.fill_sz.is_none() && msg.acc_fill_sz.is_none() {\n    return Ok(None); // not a fill, status-only update\n}","handlingStrategy":"type-guard","validationCode":"fn has_fill_qty(msg: &OKXSpreadOrderMsg) -> bool {\n    msg.fill_sz.as_deref().map_or(false, |s| !s.is_empty() && s != \"0\")\n        || msg.acc_fill_sz.as_deref().map_or(false, |s| !s.is_empty())\n}","typeGuard":"fn is_spread_fill_update(msg: &OKXSpreadOrderMsg) -> bool { has_fill_qty(msg) }","tryCatchPattern":"if !has_fill_qty(&msg) { return Ok(None); } // status-only, not a fill","preventionTips":["Route sprd-orders updates through fill parsing only when the order state indicates a fill","Pin and monitor the OKX API version for field changes"],"tags":["okx","parsing","websocket","missing-field"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}