nautechsystems/nautilus_trader · error
Failed to parse decimal from '{s}': {e}
Error message
Failed to parse decimal from '{s}': {e} What it means
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.
Source
Thrown at crates/core/src/serialization.rs:705
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut seq = serializer.serialize_seq(Some(decimals.len()))?;
for decimal in decimals {
seq.serialize_element(&decimal.to_string())?;
}
seq.end()
}
/// Parses a string to `Decimal`, returning an error if parsing fails.
///
/// # Errors
///
/// Returns an error if the string cannot be parsed as a Decimal.
pub fn parse_decimal(s: &str) -> anyhow::Result<Decimal> {
Decimal::from_str(s).map_err(|e| anyhow::anyhow!("Failed to parse decimal from '{s}': {e}"))
}
/// Parses an optional string to `Decimal`, returning `None` if the string is `None` or empty.
///
/// # Errors
///
/// Returns an error if the string cannot be parsed as a Decimal.
pub fn parse_optional_decimal(s: &Option<String>) -> anyhow::Result<Option<Decimal>> {
match s {
None => Ok(None),
Some(s) if s.is_empty() => Ok(None),
Some(s) => parse_decimal(s).map(Some),
}
}
/// Deserializes an empty string into `None`.
///
/// Many exchange APIs represent null string fields as an empty string (`""`).View on GitHub (pinned to 18893faf8b)
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").
Example fix
// before
let price = parse_decimal(raw.trim())?; // raw = "1,234.50"
// after
let cleaned = raw.trim().trim_start_matches('$').replace(',', "");
let price = parse_decimal(&cleaned)?; Defensive patterns
Strategy: validation
Validate before calling
fn can_parse_decimal(s: &str) -> bool {
let cleaned = s.trim().trim_start_matches('$').replace(',', "");
!cleaned.is_empty() && rust_decimal::Decimal::from_str(&cleaned).is_ok()
} Type guard
fn is_plain_decimal(s: &str) -> bool {
!s.trim().is_empty() && s.trim().chars().all(|c| c.is_ascii_digit() || c == '.' || c == '-')
} Try / catch
let price = parse_decimal(&cleaned)
.with_context(|| format!("bad price field: {raw:?}"))?; Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- invalid signed E18 integer for {field}: {value}
- invalid {field}='{raw}': {e}
- invalid price `{value}`: {e}
- invalid quantity `{value}`: {e}
- Failed to parse fallback quantity for ord_id={}, sz='{}': {e
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/93edef42d4156087.
Report an issue: GitHub.