{"record":{"id":"170923f2089f0ac1","repo":"nautechsystems/nautilus_trader","slug":"tick-sz-is-empty-for","errorCode":null,"errorMessage":"`tick_sz` is empty for {}","messagePattern":"`tick_sz` is empty for (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/okx/src/common/parse.rs","lineNumber":1645,"sourceCode":"/// Parses an OKX spread definition into a Nautilus crypto spread.\n///\n/// # Errors\n///\n/// 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)","sourceCodeStart":1627,"sourceCodeEnd":1663,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/okx/src/common/parse.rs#L1627-L1663","documentation":"parse_spread_instrument validates an OKX spread instrument definition before constructing a Nautilus instrument. A spread definition with an empty `tick_sz` (minimum price increment) cannot produce a valid Price, so parsing is aborted with this message naming the `sprd_id`.","triggerScenarios":"Calling parse_spread_instrument (directly or via request_spread_instrument/request_spread_instruments) with an OKX spread instrument JSON whose `tickSz` field is an empty string — typically from a pre-listing or placeholder spread record returned by the spreads endpoint.","commonSituations":"Requesting all spread instruments and iterating over records without filtering pre-open ones; stale cached instrument data; OKX API returning partially populated definitions during new spread listings.","solutions":["Filter spread instrument records with an empty `tickSz` before parsing (skip or defer them)","Re-fetch the spread instrument definition; the empty field may be transient for newly listed spreads","Check the instrument state field (`state`/`listTime`) and only parse live instruments"],"exampleFix":"// before\nfor sprd in response.data {\n    let inst = parse_spread_instrument(&sprd, ...)?; // bails on empty tickSz\n}\n// after\nfor sprd in response.data.into_iter().filter(|s| !s.tick_sz.is_empty() && !s.lot_sz.is_empty()) {\n    let inst = parse_spread_instrument(&sprd, ...)?;\n}","handlingStrategy":"validation","validationCode":"if definition.tick_sz.is_empty() || definition.lot_sz.is_empty() {\n    return Ok(None); // skip incomplete spread instrument\n}","typeGuard":null,"tryCatchPattern":"match parse_spread_instrument(&definition, ...) {\n    Ok(inst) => add(inst),\n    Err(e) if e.to_string().contains(\"is empty\") => log::debug!(\"skipped incomplete spread: {e}\"),\n    Err(e) => return Err(e),\n}","preventionTips":["Filter pre-open/incomplete spreads before parsing","Check state/listTime on spread records","Re-fetch definitions for newly listed spreads instead of failing the whole batch"],"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"}