nautechsystems/nautilus_trader · error

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

Error message

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

What it means

parse_spread_instrument parses the definition's tick_sz string into a Price to form the price increment. If tick_sz is empty or not a valid price string, the error is raised naming the value and sprd_id.

Source

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

        Currency::get_or_create_crypto_with_context(definition.base_ccy, Some(&context));
    let quote_currency =
        Currency::get_or_create_crypto_with_context(definition.quote_ccy, Some(&context));
    let settlement_currency = spread_settlement_currency(definition, underlying, quote_currency);
    let is_inverse = matches!(definition.sprd_type, OKXSpreadType::Inverse);
    let activation_ns = definition
        .list_time
        .map(parse_millisecond_timestamp)
        .ok_or_else(|| anyhow::anyhow!("`list_time` is required for {}", definition.sprd_id))?;
    let expiration_ns = definition
        .exp_time
        .map(parse_millisecond_timestamp)
        .unwrap_or_default();
    let ts_event = definition
        .u_time
        .map_or(ts_init, parse_millisecond_timestamp);

    let price_increment = Price::from_str(&definition.tick_sz).map_err(|e| {
        anyhow::anyhow!(
            "Failed to parse `tick_sz` '{}' for {}: {e}",
            definition.tick_sz,
            definition.sprd_id
        )
    })?;
    let size_increment = Quantity::from_str(&definition.lot_sz).map_err(|e| {
        anyhow::anyhow!(
            "Failed to parse `lot_sz` '{}' for {}: {e}",
            definition.lot_sz,
            definition.sprd_id
        )
    })?;
    let min_quantity = if definition.min_sz.is_empty() {
        None
    } else {
        Some(Quantity::from_str(&definition.min_sz).map_err(|e| {
            anyhow::anyhow!(
                "Failed to parse `min_sz` '{}' for {}: {e}",

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Print the raw definition and verify tick_sz is a valid non-empty numeric string
  2. Re-fetch instruments from OKX /sprd/instruments to replace the bad definition
  3. Add a pre-parse guard treating empty tick_sz as an error with a clear message
  4. Check for serde field-name/casing mismatches leaving tick_sz unset
Defensive patterns

Strategy: validation

Validate before calling

fn tick_sz_valid(def: &OKXSpreadInstrument) -> bool {
    !def.tick_sz.is_empty() && def.tick_sz.parse::<rust_decimal::Decimal>().is_ok()
}

Try / catch

let price_increment = match parse_spread_instrument(&definition, ts_init) {
    Ok(inst) => inst,
    Err(e) => { tracing::error!("tick_sz/lot_sz parse failed for {}: {e:#}", definition.sprd_id); return; }
};

Prevention

When it happens

Trigger: Calling parse_spread_instrument when the spread definition's tick_sz is empty, malformed (e.g. contains units), or uses an unparseable numeric representation.

Common situations: Missing or truncated fields in cached/manual spread definitions; OKX payload changes; fixture typos such as tick_sz vs tickSz casing.

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/534b423c93217eee. Report an issue: GitHub.