{"record":{"id":"3c46b0974c0b3b4d","repo":"nautechsystems/nautilus_trader","slug":"lot-sz-is-empty-for","errorCode":null,"errorMessage":"`lot_sz` is empty for {}","messagePattern":"`lot_sz` is empty for (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/okx/src/common/parse.rs","lineNumber":1649,"sourceCode":"/// Returns an error if the spread definition cannot be parsed.\n///\n/// # Panics\n///\n/// Panics if the constructed instrument fails validation.\npub fn parse_spread_instrument(\n    definition: &OKXSpread,\n    margin_init: Option<Decimal>,\n    margin_maint: Option<Decimal>,\n    maker_fee: Option<Decimal>,\n    taker_fee: Option<Decimal>,\n    ts_init: UnixNanos,\n) -> anyhow::Result<InstrumentAny> {\n    if definition.tick_sz.is_empty() {\n        anyhow::bail!(\"`tick_sz` is empty for {}\", definition.sprd_id);\n    }\n\n    if definition.lot_sz.is_empty() {\n        anyhow::bail!(\"`lot_sz` is empty for {}\", definition.sprd_id);\n    }\n\n    let context = format!(\"SPREAD instrument {}\", definition.sprd_id);\n    let instrument_id = parse_instrument_id(definition.sprd_id);\n    let raw_symbol = Symbol::from_ustr_unchecked(definition.sprd_id);\n    let underlying =\n        Currency::get_or_create_crypto_with_context(definition.base_ccy, Some(&context));\n    let quote_currency =\n        Currency::get_or_create_crypto_with_context(definition.quote_ccy, Some(&context));\n    let settlement_currency = spread_settlement_currency(definition, underlying, quote_currency);\n    let is_inverse = matches!(definition.sprd_type, OKXSpreadType::Inverse);\n    let activation_ns = definition\n        .list_time\n        .map(parse_millisecond_timestamp)\n        .ok_or_else(|| anyhow::anyhow!(\"`list_time` is required for {}\", definition.sprd_id))?;\n    let expiration_ns = definition\n        .exp_time\n        .map(parse_millisecond_timestamp)","sourceCodeStart":1631,"sourceCodeEnd":1667,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/okx/src/common/parse.rs#L1631-L1667","documentation":"parse_spread_instrument also validates `lot_sz` (minimum tradable quantity increment). An empty value cannot be converted to a Quantity, so parsing bails with this message naming the `sprd_id`. This check runs immediately after the `tick_sz` check.","triggerScenarios":"Calling parse_spread_instrument / request_spread_instruments with a spread definition whose `lotSz` is an empty string, typically for pre-open or placeholder spread instruments returned by OKX.","commonSituations":"Bulk-parsing all spreads without filtering incomplete records; instruments newly listed where OKX has not populated lot size yet; cached/malformed instrument snapshots.","solutions":["Filter out spread records with an empty `lotSz` (together with empty `tickSz`) before parsing","Re-fetch the instrument definition from OKX and retry","Only parse instruments whose state indicates they are live","If a legitimately live instrument has empty lotSz, report/update the adapter — the API contract expects a populated lotSz"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if definition.lot_sz.is_empty() {\n    eprintln!(\"skipping spread {} with empty lot_sz\", definition.sprd_id);\n    return Ok(None);\n}","typeGuard":null,"tryCatchPattern":"match parse_spread_instrument(&definition, ...) {\n    Ok(inst) => add(inst),\n    Err(e) if e.to_string().contains(\"lot_sz\") => log::debug!(\"skipped: {e}\"),\n    Err(e) => return Err(e),\n}","preventionTips":["Validate both tick_sz and lot_sz together before parsing","Only parse spreads with state live","Treat empty trading-parameter fields as a signal of pre-listing records"],"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"}