{"record":{"id":"1facd5e7d5ac94be","repo":"nautechsystems/nautilus_trader","slug":"empty-underlying-for-inst-id-instrument-may-be","errorCode":null,"errorMessage":"Empty underlying for {inst_id}: instrument may be pre-open or misconfigured","messagePattern":"Empty underlying for (.+?): instrument may be pre-open or misconfigured","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/okx/src/common/parse.rs","lineNumber":2120,"sourceCode":"        definition,\n        &SpotInstrumentParser,\n        margin_init,\n        margin_maint,\n        maker_fee,\n        taker_fee,\n        ts_init,\n    )\n}\n\n/// Validates that the underlying field is not empty for derivative instruments.\n///\n/// # Errors\n///\n/// Returns an error if the underlying field is empty, which typically indicates\n/// a pre-open or misconfigured instrument.\nfn validate_underlying(inst_id: Ustr, uly: Ustr) -> anyhow::Result<()> {\n    if uly.is_empty() {\n        anyhow::bail!(\n            \"Empty underlying for {inst_id}: instrument may be pre-open or misconfigured\"\n        );\n    }\n    Ok(())\n}\n\n/// Parses an OKX swap instrument definition into a Nautilus crypto perpetual.\n///\n/// # Errors\n///\n/// Returns an error if the instrument definition cannot be parsed.\n///\n/// # Panics\n///\n/// Panics if the constructed instrument fails validation.\npub fn parse_swap_instrument(\n    definition: &OKXInstrument,\n    margin_init: Option<Decimal>,","sourceCodeStart":2102,"sourceCodeEnd":2138,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/okx/src/common/parse.rs#L2102-L2138","documentation":"validate_underlying checks that an OKX derivatives instrument (SWAP, FUTURES, OPTION) has a non-empty underlying (`uly`). Without an underlying the instrument cannot be linked to its index/base assets, which usually means the instrument is in pre-open state or misconfigured, so it bails naming the `inst_id`.","triggerScenarios":"parse_swap_instrument, parse_futures_instrument, or parse_option_instrument receiving an instrument definition with an empty `uly` field — common for SWAPs (where uly can be absent for some listings) or option/pre-open records returned by the instruments endpoint.","commonSituations":"Parsing the unfiltered full instrument list at startup; newly announced SWAP/FUTURES contracts in pre-open; instruments whose `uly` is intentionally absent in certain OKX product configurations.","solutions":["Filter out instruments with an empty `uly` before calling the instrument parsers","Only parse instruments with state \"live\" and a populated `uly`/`instFamily`","Re-fetch instruments if the record may have been a transient pre-open entry","If OKX legitimately omits `uly` for a product type you use (some SWAPs), extend the parser to derive the underlying from `instId`/`instFamily` instead of failing"],"exampleFix":"// before\nfor def in response.data {\n    let inst = parse_swap_instrument(&def, ...)?; // bails on empty uly\n}\n// after\nfor def in response.data.into_iter().filter(|d| !d.uly.is_empty()) {\n    let inst = parse_swap_instrument(&def, ...)?;\n}","handlingStrategy":"validation","validationCode":"fn usable_derivative(def: &OKXInstrument) -> bool {\n    matches!(def.inst_type, \"SWAP\" | \"FUTURES\" | \"OPTION\")\n        && !def.uly.is_empty()\n        && def.state == \"live\"\n}","typeGuard":null,"tryCatchPattern":"match parse_swap_instrument(&definition, ...) {\n    Ok(inst) => add(inst),\n    Err(e) if e.to_string().contains(\"Empty underlying\") => log::debug!(\"pre-open instrument skipped: {e}\"),\n    Err(e) => return Err(e),\n}","preventionTips":["Check uly is populated before parsing SWAP/FUTURES/OPTION instruments","Skip or defer pre-open instruments rather than parsing the full list blindly","Re-fetch instrument data for affected symbols; empty uly is often transient"],"tags":["rust","okx","adapter","instrument","validation"],"backgroundTag":"empty-required-field","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"}