{"record":{"id":"b0ff56d00646c199","repo":"nautechsystems/nautilus_trader","slug":"failed-to-create-quantity-from-quantity-dec-e","errorCode":null,"errorMessage":"Failed to create quantity from {quantity_dec}: {e}","messagePattern":"Failed to create quantity from (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/okx/src/common/parse.rs","lineNumber":999,"sourceCode":"    }\n\n    // Check if spotInUseAmt is zero first\n    if spot_in_use_dec.is_zero() {\n        // No position if spotInUseAmt is zero (regardless of liability)\n        return Ok(None);\n    }\n\n    // Position side based on spotInUseAmt sign\n    let (position_side, quantity_dec) = if spot_in_use_dec.is_sign_negative() {\n        // Negative spotInUseAmt = sold (short position)\n        (PositionSide::Short, spot_in_use_dec.abs())\n    } else {\n        // Positive spotInUseAmt = bought (long position)\n        (PositionSide::Long, spot_in_use_dec)\n    };\n\n    let quantity = Quantity::from_decimal_dp(quantity_dec, size_precision)\n        .map_err(|e| anyhow::anyhow!(\"Failed to create quantity from {quantity_dec}: {e}\"))?;\n\n    let ts_last = parse_millisecond_timestamp(balance.u_time);\n\n    Ok(Some(PositionStatusReport::new(\n        account_id,\n        instrument_id,\n        position_side,\n        quantity,\n        ts_last,\n        ts_init,\n        None, // report_id\n        None, // venue_position_id is None for net mode margin positions\n        None, // avg_px_open not available from balance\n    )))\n}\n\n/// Parses an OKX position into a Nautilus [`PositionStatusReport`].\n///","sourceCodeStart":981,"sourceCodeEnd":1017,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/okx/src/common/parse.rs#L981-L1017","documentation":"parse_spot_margin_position_from_balance converts the OKX spot-in-use balance into a Nautilus quantity. Quantity::from_decimal_dp fails when the spotInUseAmt decimal cannot be represented at the instrument's size precision (wrong precision or malformed value), and the error is wrapped with the quantity value.","triggerScenarios":"Calling parse_spot_margin_position_from_balance with an OKX balance-and-position payload whose spotInUseAmt has more decimal places than size_precision, or a non-representable value (e.g. scientific notation, negative, or a wrong precision passed by the caller).","commonSituations":"Instrument definitions loaded with an incorrect size_precision for the trading pair; stale instrument metadata after an OKX lot-size change; spot-margin liability amounts with unexpected precision from the account/balance endpoint.","solutions":["Check that size_precision passed to the function matches the instrument's size increment from the OKX instruments endpoint","Log the raw spotInUseAmt and precision; verify the value has <= size_precision decimal places","Re-fetch instrument definitions so precision metadata is current","Round/normalize the quantity to size_precision before calling Quantity::from_decimal_dp"],"exampleFix":"// before\nlet quantity = Quantity::from_decimal_dp(quantity_dec, size_precision)\n    .map_err(|e| anyhow::anyhow!(\"Failed to create quantity from {quantity_dec}: {e}\"))?;\n// after\nlet quantity_dec = quantity_dec.round_dp(size_precision as u32);\nlet quantity = Quantity::from_decimal_dp(quantity_dec, size_precision)\n    .map_err(|e| anyhow::anyhow!(\"Failed to create quantity from {quantity_dec}: {e}\"))?;","handlingStrategy":"validation","validationCode":"// Rust: check precision fits before calling\nfn quantity_fits_precision(dec: rust_decimal::Decimal, precision: u8) -> bool {\n    dec.round_dp(precision as u32) == dec\n}\nassert!(quantity_fits_precision(quantity_dec, size_precision), \"quantity exceeds size precision\");","typeGuard":null,"tryCatchPattern":"match parse_spot_margin_position_from_balance(&balance, account_id, instrument_id, size_precision, ts_init) {\n    Ok(report) => report,\n    Err(e) => { tracing::error!(\"position quantity rejected: {e:#}\"); return; }\n}","preventionTips":["Always derive size_precision from the fetched OKX instrument definition, never hardcode","Re-sync instrument metadata when OKX changes lot size rules","Log raw balance payloads on parse failure for diagnosis"],"tags":["rust","okx","parsing","quantity-precision"],"backgroundTag":"invalid-argument-value","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"}