nautechsystems/nautilus_trader · error · anyhow::Error
Failed to parse {field}='{value}': {e}
Error message
Failed to parse {field}='{value}': {e} What it means
parse_price converts a raw exchange string (e.g. an instrument's tick size or lot size filter) into a Nautilus Price via Price::from_str. This error wraps the underlying parse failure and embeds the field name, raw value, and the reason, so instrument parsing can pinpoint which price-like field was malformed.
Source
Thrown at crates/adapters/bybit/src/common/parse.rs:1313
let parsed = parse_decimal(value, field)?;
Price::from_decimal_dp(parsed, precision).with_context(|| {
format!("Failed to construct Price for {field} with precision {precision}")
})
}
pub(crate) fn parse_quantity_with_precision(
value: &str,
precision: u8,
field: &str,
) -> anyhow::Result<Quantity> {
let parsed = parse_decimal(value, field)?;
Quantity::from_decimal_dp(parsed, precision).with_context(|| {
format!("Failed to construct Quantity for {field} with precision {precision}")
})
}
pub(crate) fn parse_price(value: &str, field: &str) -> anyhow::Result<Price> {
Price::from_str(value).map_err(|e| anyhow::anyhow!("Failed to parse {field}='{value}': {e}"))
}
pub(crate) fn parse_quantity(value: &str, field: &str) -> anyhow::Result<Quantity> {
Quantity::from_str(value).map_err(|e| anyhow::anyhow!("Failed to parse {field}='{value}': {e}"))
}
pub(crate) fn parse_decimal(value: &str, field: &str) -> anyhow::Result<Decimal> {
Decimal::from_str(value)
.map_err(|e| anyhow::anyhow!("Failed to parse {field}='{value}' as Decimal: {e}"))
}
pub(crate) fn parse_millis_timestamp(value: &str, field: &str) -> anyhow::Result<UnixNanos> {
let millis: u64 = value
.parse()
.with_context(|| format!("Failed to parse {field}='{value}' as u64 millis"))?;
let nanos = millis
.checked_mul(NANOSECONDS_IN_MILLISECOND)
.context("millisecond timestamp overflowed when converting to nanoseconds")?;View on GitHub (pinned to 18893faf8b)
Solutions
- Check the raw instrument payload for the named field and confirm it is a valid decimal number string.
- Treat empty strings as absent: skip/None instead of calling parse_price.
- Trim whitespace and normalize the string (no commas, thousands separators, or exponent notation if unsupported) before parsing.
- Update fixtures/adapter if the Bybit response schema changed.
Example fix
// before
let tick = parse_price(&filter.tick_size, "tick_size")?;
// after
let tick = (!filter.tick_size.is_empty())
.then(|| parse_price(filter.tick_size.trim(), "tick_size"))
.transpose()?; Defensive patterns
Strategy: validation
Validate before calling
// Rust: validate price strings before parse_price
fn valid_price(s: &str) -> bool {
let t = s.trim();
!t.is_empty() && t.parse::<f64>().map(|v| v.is_finite() && v > 0.0).unwrap_or(false)
} Type guard
fn parseable_price(s: &str) -> Option<rust_decimal::Decimal> {
let t = s.trim();
if t.is_empty() { return None; }
t.parse::<rust_decimal::Decimal>().ok()
} Try / catch
let price = parse_price(value, "tick_size")
.with_context(|| format!("instrument {} had bad tick_size", symbol))?; Prevention
- Never pass empty strings for optional price fields; use Option/skip
- Trim and strip formatting (commas, whitespace) from exchange strings
- Keep instrument fixtures copied from real exchange responses
When it happens
Trigger: parse_spot_instrument / parse_linear_instrument / parse_inverse_instrument / parse_option_instrument / extract_strike_from_symbol call parse_price with a value that Price::from_str rejects (non-numeric, empty, out-of-range, or bad precision).
Common situations: Bybit returning empty strings for optional fields (e.g. unset tick size); localization/formatting surprises; mocking fixtures with placeholder values; API schema changes moving fields so wrong values get passed as prices.
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 Bybit trigger type: '{s}', expected LastPrice, MarkP
- invalid Bybit TP/SL order type: '{s}', expected Market or Li
- invalid Bybit TP/SL mode: '{s}', expected Full or Partial
- Invalid topic format: empty topic
- Missing option_type for option instrument
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/b78c2af9118bc32d.
Report an issue: GitHub.