{"record":{"id":"6af0e56b817b10cf","repo":"nautechsystems/nautilus_trader","slug":"no-instrument-found-for-inst-id","errorCode":null,"errorMessage":"No instrument found for inst_id: {}","messagePattern":"No instrument found for inst_id: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/okx/src/websocket/parse.rs","lineNumber":1358,"sourceCode":"}\n\n/// Parses a single OKX 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_order_msg(\n    msg: &OKXOrderMsg,\n    account_id: AccountId,\n    instruments: &AHashMap<Ustr, InstrumentAny>,\n    fee_cache: &AHashMap<Ustr, Money>,\n    filled_qty_cache: &AHashMap<Ustr, Quantity>,\n    ts_init: UnixNanos,\n) -> anyhow::Result<ExecutionReport> {\n    let instrument = instruments\n        .get(&msg.inst_id)\n        .ok_or_else(|| anyhow::anyhow!(\"No instrument found for inst_id: {}\", msg.inst_id))?;\n\n    let previous_fee = fee_cache.get(&msg.ord_id).copied();\n    let previous_filled_qty = filled_qty_cache.get(&msg.ord_id).copied();\n\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(\n            &msg.acc_fill_sz,\n            previous_filled_qty,\n            instrument.size_precision(),\n        );\n\n    warn_unrecognized_order_state(msg);\n\n    match msg.state {\n        OKXOrderStatus::Filled | OKXOrderStatus::PartiallyFilled | OKXOrderStatus::Unknown\n            if has_new_fill =>\n        {","sourceCodeStart":1340,"sourceCodeEnd":1376,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/okx/src/websocket/parse.rs#L1340-L1376","documentation":"parse_order_msg maps an OKX order message's inst_id to a previously cached local instrument; if the ID is absent from the instruments map, the message cannot be translated into an ExecutionReport and this error is thrown. The library requires the instrument to be subscribed/loaded before private order stream messages are parsed.","triggerScenarios":"An OKX private 'orders' WebSocket message arrives for an instrument that was never loaded into the instruments AHashMap (no subscription, no HTTP instrument load, or cache cleared), so instruments.get(&msg.inst_id) returns None.","commonSituations":"Subscribing to the private orders channel without instruments loaded; orders placed manually on OKX's web/app UI for instruments not subscribed via the adapter; inst_id format mismatch (e.g. SPOT vs SWAP suffix variants); adapter restart wiping the cache while open orders still stream in.","solutions":["Ensure all traded instruments are requested/loaded into the instruments map before subscribing to the private orders channel","Subscribe to the instrument on this adapter instance so its definition is cached when order updates arrive","Check the inst_id string matches exactly what the adapter stores (e.g. 'BTC-USDT-SWAP' vs 'BTC-USDT')","Add a lookup-and-fetch fallback: on miss, fetch the instrument via OKX HTTP API and insert into the map, then retry parsing"],"exampleFix":"// before\nlet instrument = instruments\n    .get(&msg.inst_id)\n    .ok_or_else(|| anyhow::anyhow!(\"No instrument found for inst_id: {}\", msg.inst_id))?;\n// after\nlet instrument = match instruments.get(&msg.inst_id) {\n    Some(inst) => inst,\n    None => {\n        log::warn(\"Skipping order update for unknown instrument {inst_id}; ensure it is loaded/subscribed\");\n        return Ok(None);\n    }\n};","handlingStrategy":"validation","validationCode":"// Rust, before processing private order updates\nif !instruments.contains_key(&msg.inst_id) {\n    log::warn(\"No cached instrument for {inst_id}; loading it before parse\");\n    load_instrument(msg.inst_id)?; // fetch via HTTP and insert into map\n}","typeGuard":"fn instrument_cached(map: &AHashMap<Ustr, InstrumentAny>, inst_id: &Ustr) -> Option<InstrumentAny> {\n    map.get(inst_id).copied()\n}","tryCatchPattern":"match parse_order_msg(&msg, &instruments, account_id, &fee_cache, &filled_qty_cache, ts_init) {\n    Ok(report) => dispatch(report),\n    Err(e) if e.to_string().starts_with(\"No instrument found for inst_id\") => {\n        log::warn(\"{e}; ensure instrument is loaded before private stream messages\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Load all instruments you trade into the adapter before opening the private orders channel","Re-sync the instrument cache on adapter restart while orders may still be open","Keep inst_id strings verbatim from OKX (no reformatting/case changes)","Reconcile open orders at startup and backfill any missing instrument definitions"],"tags":["okx","websocket","parsing","instrument-lookup","cache-miss"],"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"}