{"record":{"id":"8ae5e92e46c1f402","repo":"nautechsystems/nautilus_trader","slug":"no-mark-price-returned-from-okx","errorCode":null,"errorMessage":"No mark price returned from OKX","messagePattern":"No mark price returned from OKX","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/okx/src/http/client.rs","lineNumber":2807,"sourceCode":"    pub async fn request_mark_price(\n        &self,\n        instrument_id: InstrumentId,\n    ) -> anyhow::Result<MarkPriceUpdate> {\n        let inst = self.instrument_from_cache(instrument_id.symbol.inner())?;\n        let mut params = GetMarkPriceParamsBuilder::default();\n        params.inst_type(okx_instrument_type(&inst)?);\n        params.inst_id(instrument_id.symbol.inner());\n        let params = params.build().map_err(|e| anyhow::anyhow!(e))?;\n\n        let resp = self\n            .inner\n            .get_mark_price(params)\n            .await\n            .map_err(|e| anyhow::anyhow!(e))?;\n\n        let raw = resp\n            .first()\n            .ok_or_else(|| anyhow::anyhow!(\"No mark price returned from OKX\"))?;\n        let ts_init = self.generate_ts_init();\n\n        let mark_price =\n            parse_mark_price_update(raw, instrument_id, inst.price_precision(), ts_init)\n                .map_err(|e| anyhow::anyhow!(e))?;\n        Ok(mark_price)\n    }\n\n    /// Requests the current price limits for the `instrument_id` from OKX.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the HTTP request fails or no price limit is returned.\n    pub async fn request_price_limit(\n        &self,\n        instrument_id: InstrumentId,\n    ) -> anyhow::Result<OKXPriceLimit> {\n        let mut params = GetPriceLimitParamsBuilder::default();","sourceCodeStart":2789,"sourceCodeEnd":2825,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/okx/src/http/client.rs#L2789-L2825","documentation":"Raised in `request_mark_price` when OKX returns HTTP success but an empty data array — no mark-price record exists for the requested instrument. The adapter requires exactly one record and treats the empty result as an error.","triggerScenarios":"Calling `request_mark_price` for an instrument_id whose inst_id/inst_type yields no rows on OKX: delisted instrument, expired derivative, spot pair without mark price, or wrong venue/symbol in config.","commonSituations":"Polling mark price for an expired future or settled option; symbol configured with the wrong venue suffix; querying before the instrument began trading; OKX temporarily returning empty data during maintenance.","solutions":["Verify the instrument is currently listed and trading on OKX.","Check the inst_type derived from the cached instrument matches the instrument (SWAP/FUTURES/OPTION vs SPOT).","Guard the caller: skip or defer mark-price requests for expired/delisted instruments.","Retry later if OKX is in maintenance; empty responses during downtime are transient."],"exampleFix":"// before\nlet mark = client.request_mark_price(&expired_future_id).await?;\n// after\nif !instrument_is_active(&expired_future_id) { return Ok(None); }\nlet mark = client.request_mark_price(&expired_future_id).await?;","handlingStrategy":"validation","validationCode":"if instrument.expiry_unix_nanos() <= clock.timestamp_ns() {\n    // skip mark price for expired instruments\n    return Ok(None);\n}","typeGuard":"fn is_active(now_unix: i64, inst: &InstrumentAny) -> bool {\n    inst.expiration().map_or(true, |exp| exp.as_unix_nanos() > now_unix)\n}","tryCatchPattern":"match client.request_mark_price(&inst_id).await {\n    Ok(mp) => mp,\n    Err(e) if e.to_string().contains(\"No mark price returned\") => {\n        log::warn!(\"no OKX mark price for {inst_id}; skipping\");\n        Default::default()\n    }\n    Err(e) => return Err(e),\n};","preventionTips":["Track instrument expiry and stop requesting data once expired.","Confirm venue/instrument configuration matches live OKX listings at startup.","Subscribe to delisting notices and remove instruments from polling sets.","Handle OKX maintenance windows where data can be temporarily empty."],"tags":["not-found","empty-response","okx","market-data"],"backgroundTag":"empty-result-set","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"}