{"record":{"id":"76a9dc51e845ff0c","repo":"nautechsystems/nautilus_trader","slug":"failed-to-parse-ct-mult-for-e","errorCode":null,"errorMessage":"Failed to parse `ct_mult` '{}' for {}: {e}","messagePattern":"Failed to parse `ct_mult` '(.+?)' for (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/okx/src/common/parse.rs","lineNumber":1903,"sourceCode":"    margin_maint: Option<Decimal>,\n    maker_fee: Option<Decimal>,\n    taker_fee: Option<Decimal>,\n}\n\n/// Parses the multiplier as the product of ct_mult and ct_val.\n///\n/// For SPOT instruments where both fields are empty, returns None.\n/// For derivatives, multiplies the two fields to get the final multiplier.\nfn parse_multiplier_product(definition: &OKXInstrument) -> anyhow::Result<Option<Quantity>> {\n    if definition.ct_mult.is_empty() && definition.ct_val.is_empty() {\n        return Ok(None);\n    }\n\n    let mult_value = if definition.ct_mult.is_empty() {\n        Decimal::ONE\n    } else {\n        Decimal::from_str(&definition.ct_mult).map_err(|e| {\n            anyhow::anyhow!(\n                \"Failed to parse `ct_mult` '{}' for {}: {e}\",\n                definition.ct_mult,\n                definition.inst_id\n            )\n        })?\n    };\n\n    let val_value = if definition.ct_val.is_empty() {\n        Decimal::ONE\n    } else {\n        Decimal::from_str(&definition.ct_val).map_err(|e| {\n            anyhow::anyhow!(\n                \"Failed to parse `ct_val` '{}' for {}: {e}\",\n                definition.ct_val,\n                definition.inst_id\n            )\n        })?\n    };","sourceCodeStart":1885,"sourceCodeEnd":1921,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/okx/src/common/parse.rs#L1885-L1921","documentation":"parse_multiplier_product computes the contract multiplier from ct_mult and ct_val. When ct_mult is non-empty but not a valid decimal string, Decimal::from_str fails and this error is raised naming the value and inst_id.","triggerScenarios":"Calling any of parse_swap_instrument / parse_futures_instrument / parse_option_instrument / parse_specific_fields on an OKX instrument definition whose ct_mult field is populated with a non-decimal string.","commonSituations":"Placeholder or corrupt values in cached instrument JSON; OKX payload schema drift; manual fixtures with wrong values (e.g. '1x' instead of '1').","solutions":["Inspect ct_mult in the failing definition; it must be a plain decimal string or empty","Re-fetch instrument definitions from the OKX /public/instruments endpoint","Strip units/formatting from ct_mult before parsing","If ct_mult is unknown, leave it empty so the parser defaults it to Decimal::ONE"],"exampleFix":"// before\n\"ctMult\": \"2x\"\n// after\n\"ctMult\": \"2\"","handlingStrategy":"validation","validationCode":"fn ct_mult_valid(def: &OKXInstrument) -> bool {\n    def.ct_mult.is_empty() || def.ct_mult.parse::<rust_decimal::Decimal>().is_ok()\n}","typeGuard":null,"tryCatchPattern":"let multiplier = match parse_multiplier_product(&definition) {\n    Ok(m) => m,\n    Err(e) => { tracing::error!(\"contract multiplier parse failed: {e:#}\"); return; }\n};","preventionTips":["Store ct_mult as a plain decimal string, never with unit suffixes","Validate instrument JSON fields when writing to cache","Re-sync definitions from OKX /public/instruments regularly"],"tags":["rust","okx","parsing","decimal"],"backgroundTag":"invalid-argument-format","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"}