nautechsystems/nautilus_trader · error

Failed to parse `stk` '{}' for {}: {e}

Error message

Failed to parse `stk` '{}' for {}: {e}

What it means

Thrown when the OKX `stk` (strike price) string fails to parse into a Nautilus `Price`. The strike is mandatory for options; an unparseable decimal value aborts construction, reporting the raw string and inst_id alongside the underlying Price parse error.

Source

Thrown at crates/adapters/okx/src/common/parse.rs:2502

    let (underlying_str, quote_ccy_str) = definition.uly.split_once('-').ok_or_else(|| {
        anyhow::anyhow!(
            "Invalid underlying '{}' for {}: expected format 'BASE-QUOTE'",
            definition.uly,
            definition.inst_id
        )
    })?;

    let instrument_id = parse_instrument_id(definition.inst_id);
    let raw_symbol = Symbol::from_ustr_unchecked(definition.inst_id);
    let underlying = Currency::get_or_create_crypto_with_context(underlying_str, Some(&context));
    let option_kind: OptionKind = OptionKind::try_from(definition.opt_type).map_err(|kind| {
        anyhow::anyhow!(
            "Unsupported `optType` '{kind:?}' for {}: cannot map to Nautilus OptionKind",
            definition.inst_id
        )
    })?;
    let strike_price = Price::from_str(&definition.stk).map_err(|e| {
        anyhow::anyhow!(
            "Failed to parse `stk` '{}' for {}: {e}",
            definition.stk,
            definition.inst_id
        )
    })?;
    let quote_currency = Currency::get_or_create_crypto_with_context(quote_ccy_str, Some(&context));
    let settlement_currency =
        Currency::get_or_create_crypto_with_context(definition.settle_ccy, Some(&context));

    let is_inverse = if definition.ct_type == OKXContractType::None {
        settlement_currency == underlying
    } else {
        matches!(definition.ct_type, OKXContractType::Inverse)
    };

    let listing_time = definition
        .list_time
        .ok_or_else(|| anyhow::anyhow!("`list_time` is required for {}", definition.inst_id))?;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the raw `stk` value for the inst_id and fix the source data.
  2. Normalize the strike to plain decimal notation before parsing.
  3. Skip options with unusable strike values instead of failing the entire instrument load.

Example fix

// before
stk: "52000.00$"  // trailing unit breaks parse
// after
stk: "52000.00"
Defensive patterns

Strategy: validation

Validate before calling

if definition.stk.parse::<f64>().map(|v| v <= 0.0).unwrap_or(true) {
    eprintln!("skipping {}: bad strike {}", definition.inst_id, definition.stk);
    return Ok(None);
}

Type guard

fn valid_strike(s: &str) -> bool {
    s.parse::<f64>().map(|v| v.is_finite() && v > 0.0).unwrap_or(false)
}

Try / catch

match Price::from_str(&definition.stk) {
    Ok(p) => p,
    Err(e) => return Err(anyhow!("bad strike for {}: {e}", definition.inst_id)),
}

Prevention

When it happens

Trigger: `parse_option_instrument` via `parse_instrument_any` receives a definition whose `stk` is non-numeric, negative, empty-but-not-guarded, or exceeds Price precision bounds.

Common situations: Corrupt OKX responses or third-party data mirrors; fixtures with placeholder strike values; exponent-notation strikes rejected by Price::from_str.

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/9b1e9d22e2ce05f7. Report an issue: GitHub.