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

  1. Check the raw instrument payload for the named field and confirm it is a valid decimal number string.
  2. Treat empty strings as absent: skip/None instead of calling parse_price.
  3. Trim whitespace and normalize the string (no commas, thousands separators, or exponent notation if unsupported) before parsing.
  4. 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

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.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/b78c2af9118bc32d. Report an issue: GitHub.