{"record":{"id":"45b9dccc35184ee6","repo":"nautechsystems/nautilus_trader","slug":"failed-to-parse-position-quantity-for-instrum","errorCode":null,"errorMessage":"Failed to parse position quantity '{}' for instrument {}: {e:?}","messagePattern":"Failed to parse position quantity '(.+?)' for instrument (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/okx/src/common/parse.rs","lineNumber":1042,"sourceCode":"///\n/// - **Long/Short mode** (`posSide=\"long\"` or `\"short\"`): The `pos` field is always\n///   positive regardless of side. Position side is determined from the `posSide` field.\n///   Position IDs are suffixed with `-LONG` or `-SHORT` for uniqueness.\n///\n/// See: <https://www.okx.com/docs-v5/en/#trading-account-rest-api-get-positions>\n///\n/// # Errors\n///\n/// Returns an error if any numeric fields cannot be parsed into their target types.\npub fn parse_position_status_report(\n    position: &OKXPosition,\n    account_id: AccountId,\n    instrument_id: InstrumentId,\n    size_precision: u8,\n    ts_init: UnixNanos,\n) -> anyhow::Result<PositionStatusReport> {\n    let pos_dec = Decimal::from_str(&position.pos).map_err(|e| {\n        anyhow::anyhow!(\n            \"Failed to parse position quantity '{}' for instrument {}: {e:?}\",\n            position.pos,\n            instrument_id\n        )\n    })?;\n\n    // For SPOT/MARGIN: determine position side and quantity based on pos_ccy\n    // - If pos_ccy = base currency: LONG position, pos is in base currency\n    // - If pos_ccy = quote currency: SHORT position, pos is in quote currency (needs conversion)\n    // - If pos_ccy is empty: FLAT position (no position)\n    let (position_side, quantity_dec) = if position.inst_type == OKXInstrumentType::Spot\n        || position.inst_type == OKXInstrumentType::Margin\n    {\n        // Extract base and quote currencies from instrument symbol\n        let (base_ccy, quote_ccy) = parse_base_quote_from_symbol(instrument_id.symbol.as_str())?;\n\n        let pos_ccy = position.pos_ccy.as_str();\n","sourceCodeStart":1024,"sourceCodeEnd":1060,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/okx/src/common/parse.rs#L1024-L1060","documentation":"parse_position_status_report parses the `pos` field of an OKX position response into a Decimal. If the string is empty or not a valid decimal number, the error is raised naming the position quantity and instrument.","triggerScenarios":"Calling parse_position_status_report when position.pos is an empty string, contains formatting characters, or is otherwise not parseable by Decimal::from_str.","commonSituations":"Flat/closed positions where OKX returns an empty pos field; a change in the OKX positions API payload; feeding in a manually crafted or cached JSON record with missing fields.","solutions":["Check position.pos is a non-empty valid decimal string before calling the parser","Skip or zero-fill positions with empty pos values before parsing","Re-fetch positions from the OKX positions endpoint to replace stale/corrupt records","Add a test fixture matching the actual OKX payload shape"],"exampleFix":"// before\nlet report = parse_position_status_report(&position, account_id, instrument_id, precision, ts_init)?;\n// after\nif position.pos.is_empty() {\n    return Ok(PositionStatusReport::closed(account_id, instrument_id, ts_init));\n}\nlet report = parse_position_status_report(&position, account_id, instrument_id, precision, ts_init)?;","handlingStrategy":"validation","validationCode":"fn is_valid_position_qty(pos: &str) -> bool {\n    !pos.is_empty() && pos.parse::<rust_decimal::Decimal>().is_ok()\n}","typeGuard":null,"tryCatchPattern":"match parse_position_status_report(&position, account_id, instrument_id, size_precision, ts_init) {\n    Ok(report) => reports.push(report),\n    Err(e) => tracing::warn!(\"skipping unparseable position for {instrument_id}: {e:#}\"),\n}","preventionTips":["Treat empty pos as a flat/closed position before parsing","Validate fixtures against the live OKX positions payload schema","Keep adapter and API versions aligned"],"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"}