nautechsystems/nautilus_trader · error · anyhow::Error

invalid price for '{key}': '{s}'

Error message

invalid price for '{key}': '{s}'

What it means

For trigger-price parameters ('tp_trigger_price' and 'sl_trigger_price'), parse_bybit_tp_sl_params parses the string as f64 and rejects values that fail to parse or (in the follow-up check) are non-finite/negative. This specific error fires when the string cannot be parsed as a number at all.

Source

Thrown at crates/adapters/bybit/src/common/parse.rs:1822

        if p.as_f64() < 0.0 {
            anyhow::bail!("invalid 'stop_loss' price: '{s}', expected a non-negative value");
        }
        result.stop_loss = Some(p);
    }

    for (key, setter) in [
        (
            "tp_limit_price",
            &mut result.tp_limit_price as &mut Option<String>,
        ),
        ("sl_limit_price", &mut result.sl_limit_price),
        ("tp_trigger_price", &mut result.tp_trigger_price),
        ("sl_trigger_price", &mut result.sl_trigger_price),
    ] {
        if let Some(s) = get_price_str(params, key) {
            let v: f64 = s
                .parse()
                .map_err(|_| anyhow::anyhow!("invalid price for '{key}': '{s}'"))?;

            if !v.is_finite() || v < 0.0 {
                anyhow::bail!(
                    "invalid price for '{key}': '{s}', expected a finite non-negative number"
                );
            }
            *setter = Some(s);
        }
    }

    if let Some(s) = params.get_str("tp_trigger_by") {
        result.tp_trigger_by = Some(parse_trigger_type(s)?);
    }

    if let Some(s) = params.get_str("sl_trigger_by") {
        result.sl_trigger_by = Some(parse_trigger_type(s)?);
    }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure trigger price params are clean numeric strings, e.g. "65000.5" (trim whitespace, no separators/units).
  2. Validate with a parse check before submitting: value.parse::<f64>() and confirm finite and >= 0.
  3. Omit the trigger-price keys when the feature is not used instead of sending empty values.
  4. Sanitize upstream numeric formatting so no commas or unit suffixes leak into the string.

Example fix

// before
params.insert("sl_trigger_price".into(), trigger_price_input.to_string());
// after
let v: f64 = trigger_price_input.trim().parse()?;
anyhow::ensure!(v.is_finite() && v >= 0.0, "sl_trigger_price must be finite non-negative");
params.insert("sl_trigger_price".into(), format!("{v}"));
Defensive patterns

Strategy: validation

Validate before calling

// Rust: validate trigger prices before building order params
fn valid_trigger(s: &str) -> bool {
    s.trim().parse::<f64>().map(|v| v.is_finite() && v >= 0.0).unwrap_or(false)
}
if !valid_trigger(&sl_trigger) { anyhow::bail!("bad sl_trigger_price: {sl_trigger}"); }

Type guard

fn parse_trigger(s: &str) -> Option<f64> {
    s.trim().parse::<f64>().ok().filter(|v| v.is_finite() && *v >= 0.0)
}

Try / catch

let p = parse_bybit_tp_sl_params(&params)
    .inspect_err(|e| log::error!("invalid TP/SL trigger params: {e:#}"))?;

Prevention

When it happens

Trigger: Order params contain 'tp_trigger_price' or 'sl_trigger_price' with a value that f64::from_str rejects — empty string, descriptive text, numbers with units ('65000 USD'), or comma-formatted numbers.

Common situations: Config-driven strategies with placeholder trigger values; strings carrying thousands separators ('65,000.5'); accidentally passing the key with an empty value from a partially-filled UI/config; prior step producing 'NaN'.

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/6d4558c979188ac6. Report an issue: GitHub.