{"record":{"id":"1b94da3adb9ad179","repo":"nautechsystems/nautilus_trader","slug":"failed-to-parse-field-value-as-decimal-e","errorCode":null,"errorMessage":"Failed to parse {field}='{value}' as Decimal: {e}","messagePattern":"Failed to parse (.+?)='(.+?)' as Decimal: (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/bybit/src/common/parse.rs","lineNumber":1322,"sourceCode":"    field: &str,\n) -> anyhow::Result<Quantity> {\n    let parsed = parse_decimal(value, field)?;\n    Quantity::from_decimal_dp(parsed, precision).with_context(|| {\n        format!(\"Failed to construct Quantity for {field} with precision {precision}\")\n    })\n}\n\npub(crate) fn parse_price(value: &str, field: &str) -> anyhow::Result<Price> {\n    Price::from_str(value).map_err(|e| anyhow::anyhow!(\"Failed to parse {field}='{value}': {e}\"))\n}\n\npub(crate) fn parse_quantity(value: &str, field: &str) -> anyhow::Result<Quantity> {\n    Quantity::from_str(value).map_err(|e| anyhow::anyhow!(\"Failed to parse {field}='{value}': {e}\"))\n}\n\npub(crate) fn parse_decimal(value: &str, field: &str) -> anyhow::Result<Decimal> {\n    Decimal::from_str(value)\n        .map_err(|e| anyhow::anyhow!(\"Failed to parse {field}='{value}' as Decimal: {e}\"))\n}\n\npub(crate) fn parse_millis_timestamp(value: &str, field: &str) -> anyhow::Result<UnixNanos> {\n    let millis: u64 = value\n        .parse()\n        .with_context(|| format!(\"Failed to parse {field}='{value}' as u64 millis\"))?;\n    let nanos = millis\n        .checked_mul(NANOSECONDS_IN_MILLISECOND)\n        .context(\"millisecond timestamp overflowed when converting to nanoseconds\")?;\n    Ok(UnixNanos::from(nanos))\n}\n\nfn resolve_settlement_currency(\n    settle_coin: &str,\n    base_currency: Currency,\n    quote_currency: Currency,\n) -> anyhow::Result<Currency> {\n    if settle_coin.eq_ignore_ascii_case(base_currency.code.as_str()) {","sourceCodeStart":1304,"sourceCodeEnd":1340,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/bybit/src/common/parse.rs#L1304-L1340","documentation":"parse_decimal converts an exchange string into a rust_decimal Decimal. This error wraps the conversion failure with the field name and raw value, and is used widely: instrument parsing, funding rates, and the precision-based price/quantity parsers all route raw strings through it.","triggerScenarios":"Any caller (parse_spot/linear/inverse_instrument, parse_funding_rate, parse_price_with_precision, parse_quantity_with_precision) supplies a string Decimal::from_str cannot parse: empty, non-numeric text, or malformed decimals.","commonSituations":"Bybit returning empty strings for optional/unset fields (common for funding interval or basis rate on newly listed symbols); mis-parsed JSON nesting causing a wrong value type string; test fixtures with dummy values; NaN/Infinity strings.","solutions":["Inspect the raw value for the named field; confirm it is a finite decimal string.","Handle empty strings explicitly (default/skip) before calling parse_decimal.","Trim and normalize (no commas, no 'NaN'/'inf').","Update the adapter if the Bybit response schema shifted fields."],"exampleFix":"// before\nlet funding = parse_decimal(&resp.current_funding_rate, \"current_funding_rate\")?;\n// after\nlet raw = resp.current_funding_rate.trim();\nlet funding = if raw.is_empty() { Decimal::ZERO } else { parse_decimal(raw, \"current_funding_rate\")? };","handlingStrategy":"validation","validationCode":"// Rust: safe decimal parse helper used before parse_decimal\nfn parse_decimal_safe(s: &str) -> Option<rust_decimal::Decimal> {\n    let t = s.trim();\n    if t.is_empty() || t.eq_ignore_ascii_case(\"nan\") || t.eq_ignore_ascii_case(\"inf\") { return None; }\n    t.parse::<rust_decimal::Decimal>().ok()\n}","typeGuard":"fn is_decimal_string(s: &str) -> bool { !s.trim().is_empty() && s.trim().parse::<rust_decimal::Decimal>().is_ok() }","tryCatchPattern":"let v = parse_decimal(raw, field).unwrap_or_else(|e| {\n    log::warn!(\"defaulting {field} to zero: {e:#}\");\n    Decimal::ZERO\n});","preventionTips":["Handle empty-string optional fields (funding rate, basis rate) before parsing","Trim all exchange-provided numeric strings","Cover newly listed symbols (empty optional fields) in tests"],"tags":["parsing","decimal","bybit"],"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-14T05:17:10.506Z"}