{"record":{"id":"e5c6219d18ecfa1c","repo":"nautechsystems/nautilus_trader","slug":"no-instrument-found-for-sprd-id","errorCode":null,"errorMessage":"No instrument found for sprd_id: {}","messagePattern":"No instrument found for sprd_id: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/okx/src/websocket/parse.rs","lineNumber":1423,"sourceCode":"    }\n}\n\n/// Parses a single OKX spread order message into an [`ExecutionReport`].\n///\n/// # Errors\n///\n/// Returns an error if the instrument cannot be found or if parsing the\n/// underlying order payload fails.\npub fn parse_spread_order_msg(\n    msg: &OKXSpreadOrder,\n    account_id: AccountId,\n    instruments: &AHashMap<Ustr, InstrumentAny>,\n    filled_qty_cache: &AHashMap<Ustr, Quantity>,\n    ts_init: UnixNanos,\n) -> anyhow::Result<ExecutionReport> {\n    let instrument = instruments\n        .get(&msg.sprd_id)\n        .ok_or_else(|| anyhow::anyhow!(\"No instrument found for sprd_id: {}\", msg.sprd_id))?;\n    let previous_filled_qty = filled_qty_cache.get(&msg.ord_id).copied();\n    let has_new_fill = (!msg.fill_sz.is_empty() && msg.fill_sz != \"0\")\n        || !msg.trade_id.is_empty()\n        || has_acc_fill_sz_increased_value(\n            Some(msg.acc_fill_sz.as_str()),\n            previous_filled_qty,\n            instrument.size_precision(),\n        );\n\n    match msg.state {\n        OKXOrderStatus::Filled | OKXOrderStatus::PartiallyFilled if has_new_fill => {\n            match parse_spread_order_fill_report(\n                msg,\n                instrument,\n                account_id,\n                previous_filled_qty,\n                ts_init,\n            )? {","sourceCodeStart":1405,"sourceCodeEnd":1441,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/okx/src/websocket/parse.rs#L1405-L1441","documentation":"parse_spread_order_msg resolves an OKX spread order message's sprd_id against the local instrument cache; an unknown sprd_id means the spread's legs/definition were never loaded, so no ExecutionReport can be built and this error is thrown. Spread instruments must be explicitly loaded before spread order stream messages are parsed.","triggerScenarios":"A private spread 'orders' ('sprd-orders') WebSocket message arrives whose sprd_id is not present in the instruments AHashMap — the spread was not subscribed/loaded on this adapter session.","commonSituations":"Spread orders placed via OKX web UI for spreads the adapter never instantiated; sprd_id string mismatch vs cached key; adapter restart losing cached spread instruments while live spread orders stream updates.","solutions":["Load/subscribe the spread instrument on the adapter before expecting spread order updates","Verify the sprd_id string matches the cached key exactly (OKX spread IDs like 'BTC-USDT_BTC-USDT-250328')","On unknown sprd_id, fetch the spread definition via OKX HTTP API and insert into the instruments cache, then re-parse","Skip and log unknown-spread order messages instead of failing the dispatch loop"],"exampleFix":"// before\nlet instrument = instruments\n    .get(&msg.sprd_id)\n    .ok_or_else(|| anyhow::anyhow!(\"No instrument found for sprd_id: {}\", msg.sprd_id))?;\n// after\nlet instrument = match instruments.get(&msg.sprd_id) {\n    Some(inst) => inst,\n    None => {\n        log::warn(\"Skipping spread order for unknown sprd_id {sprd_id}; load the spread first\");\n        return Ok(None);\n    }\n};","handlingStrategy":"validation","validationCode":"// Rust, before parsing spread order updates\nif !instruments.contains_key(&msg.sprd_id) {\n    log::warn(\"Spread {sprd_id} not cached; loading spread definition first\");\n    load_spread_instrument(msg.sprd_id)?;\n}","typeGuard":"fn spread_cached(map: &AHashMap<Ustr, InstrumentAny>, sprd_id: &Ustr) -> bool {\n    map.contains_key(sprd_id)\n}","tryCatchPattern":"match parse_spread_order_msg(&msg, &instruments, account_id, &filled_qty_cache, ts_init) {\n    Ok(report) => dispatch(report),\n    Err(e) if e.to_string().starts_with(\"No instrument found for sprd_id\") => {\n        log::warn(\"{e}; subscribe/load the spread before expecting its order updates\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Explicitly load every spread instrument the strategy trades before enabling the spread orders stream","Keep sprd_id strings exactly as OKX reports them","Persist/restore spread instrument cache across adapter restarts","Reconcile open spread orders at startup to backfill missing definitions"],"tags":["okx","websocket","parsing","spread","instrument-lookup"],"backgroundTag":"entity-not-found","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}