{"record":{"id":"1a01c82b51254e8a","repo":"nautechsystems/nautilus_trader","slug":"failed-to-parse-ct-val-for-e","errorCode":null,"errorMessage":"Failed to parse `ct_val` '{}' for {}: {e}","messagePattern":"Failed to parse `ct_val` '(.+?)' for (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/okx/src/common/parse.rs","lineNumber":1915,"sourceCode":"    }\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    };\n\n    let product = mult_value * val_value;\n    Ok(Some(Quantity::from(product.to_string())))\n}\n\n/// Trait for instrument-specific parsing logic.\ntrait InstrumentParser {\n    /// Parses instrument-specific fields and creates the final instrument.\n    fn parse_specific_fields(\n        &self,\n        definition: &OKXInstrument,\n        common: CommonInstrumentData,","sourceCodeStart":1897,"sourceCodeEnd":1933,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/okx/src/common/parse.rs#L1897-L1933","documentation":"parse_multiplier_product parses ct_val (contract value per unit) into a Decimal. A non-empty ct_val that cannot be parsed as a decimal raises this error naming the value and inst_id. Empty ct_val defaults to Decimal::ONE.","triggerScenarios":"Calling parse_swap_instrument / parse_futures_instrument / parse_option_instrument / parse_specific_fields with an instrument definition where ct_val contains a non-decimal string (e.g. scientific notation the Decimal parser rejects, currency-annotated values, or empty-vs-garbage confusion).","commonSituations":"Malformed cached instrument metadata; OKX adding fields or changing formats for newer contract types; fixtures hand-written with wrong ct_val values.","solutions":["Verify ct_val in the failing payload is a plain decimal string (or empty to default to 1)","Re-fetch the instrument definition from OKX /public/instruments","Normalize the string (trim, strip currency suffixes) before parsing","Leave ct_val empty when the contract multiplier should default to 1"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"fn ct_val_valid(def: &OKXInstrument) -> bool {\n    def.ct_val.is_empty() || def.ct_val.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!(\"ct_val parse failed for {}: {e:#}\", definition.inst_id); return; }\n};","preventionTips":["Leave ct_val empty when defaulting to 1 is intended","Watch OKX changelogs for ct_val format changes per contract type","Verify hand-written fixtures use plain decimal strings"],"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"}