{"record":{"id":"93edef42d4156087","repo":"nautechsystems/nautilus_trader","slug":"failed-to-parse-decimal-from-s-e","errorCode":null,"errorMessage":"Failed to parse decimal from '{s}': {e}","messagePattern":"Failed to parse decimal from '(.+?)': (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/core/src/serialization.rs","lineNumber":705,"sourceCode":"    serializer: S,\n) -> Result<S::Ok, S::Error>\nwhere\n    S: Serializer,\n{\n    let mut seq = serializer.serialize_seq(Some(decimals.len()))?;\n    for decimal in decimals {\n        seq.serialize_element(&decimal.to_string())?;\n    }\n    seq.end()\n}\n\n/// Parses a string to `Decimal`, returning an error if parsing fails.\n///\n/// # Errors\n///\n/// Returns an error if the string cannot be parsed as a Decimal.\npub fn parse_decimal(s: &str) -> anyhow::Result<Decimal> {\n    Decimal::from_str(s).map_err(|e| anyhow::anyhow!(\"Failed to parse decimal from '{s}': {e}\"))\n}\n\n/// Parses an optional string to `Decimal`, returning `None` if the string is `None` or empty.\n///\n/// # Errors\n///\n/// Returns an error if the string cannot be parsed as a Decimal.\npub fn parse_optional_decimal(s: &Option<String>) -> anyhow::Result<Option<Decimal>> {\n    match s {\n        None => Ok(None),\n        Some(s) if s.is_empty() => Ok(None),\n        Some(s) => parse_decimal(s).map(Some),\n    }\n}\n\n/// Deserializes an empty string into `None`.\n///\n/// Many exchange APIs represent null string fields as an empty string (`\"\"`).","sourceCodeStart":687,"sourceCodeEnd":723,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/core/src/serialization.rs#L687-L723","documentation":"parse_decimal converts a string to a fixed-point Decimal via Decimal::from_str. If the string is not a syntactically valid decimal (bad characters, multiple dots, empty, out-of-scale exponent), the underlying parse error is wrapped with the offending input. This is a strict format-validation error for numeric strings.","triggerScenarios":"parse_decimal(s) with any string not parseable as Decimal: \"1,000.5\" (comma separators), \"$12.50\" (currency symbols), \"\" (empty), \"1.2.3\", scientific notation beyond Decimal support, or locale-formatted numbers.","commonSituations":"Parsing prices/quantities from CSV, exchange responses, or user config where values carry thousands separators, currency symbols, or whitespace; locale differences; empty cells in a file.","solutions":["Sanitize the string first: trim whitespace, strip currency symbols and thousands separators.","Use parse_optional_decimal if the value may legitimately be empty, so None is handled.","Fix the data source/serialization so numbers arrive as plain decimal text (e.g. \"1000.50\")."],"exampleFix":"// before\nlet price = parse_decimal(raw.trim())?; // raw = \"1,234.50\"\n// after\nlet cleaned = raw.trim().trim_start_matches('$').replace(',', \"\");\nlet price = parse_decimal(&cleaned)?;","handlingStrategy":"validation","validationCode":"fn can_parse_decimal(s: &str) -> bool {\n    let cleaned = s.trim().trim_start_matches('$').replace(',', \"\");\n    !cleaned.is_empty() && rust_decimal::Decimal::from_str(&cleaned).is_ok()\n}","typeGuard":"fn is_plain_decimal(s: &str) -> bool {\n    !s.trim().is_empty() && s.trim().chars().all(|c| c.is_ascii_digit() || c == '.' || c == '-')\n}","tryCatchPattern":"let price = parse_decimal(&cleaned)\n    .with_context(|| format!(\"bad price field: {raw:?}\"))?;","preventionTips":["Strip locale formatting (commas, currency symbols, spaces) before parsing.","Use parse_optional_decimal for fields that may be empty.","Prefer machine-readable numeric formats in files and API responses feeding this parser."],"tags":["parsing","decimal","rust"],"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"}