nautechsystems/nautilus_trader · error · anyhow::Error

unsupported linear contract variant: {other:?}

Error message

unsupported linear contract variant: {other:?}

What it means

parse_linear_instrument matches on BybitContractType to decide whether a linear instrument is a LinearPerpetual (CryptoPerpetual) or LinearFutures (CryptoFuture). Any other contract-type variant returned by the exchange hits a catch-all arm that returns this error. It signals an exchange contract type the adapter does not know how to map to a Nautilus instrument type.

Source

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

                .size_increment(size_increment)
                .maybe_lot_size(lot_size)
                .maybe_max_quantity(max_quantity)
                .maybe_min_quantity(min_quantity)
                .maybe_min_notional(min_notional)
                .maybe_max_price(max_price)
                .maybe_min_price(min_price)
                .margin_init(default_margin())
                .margin_maint(default_margin())
                .maker_fee(maker_fee)
                .taker_fee(taker_fee)
                .maybe_info(info)
                .ts_event(ts_event)
                .ts_init(ts_init)
                .build()
                .unwrap();
            Ok(InstrumentAny::CryptoFuture(instrument))
        }
        other => Err(anyhow::anyhow!(
            "unsupported linear contract variant: {other:?}"
        )),
    }
}

/// Parses Bybit's `minNotionalValue` string (when present) into a `Money` value
/// denominated in the instrument's quote currency. Returns `Ok(None)` if the
/// field is absent or an empty string.
fn parse_optional_notional(
    raw: Option<&str>,
    currency: Currency,
    field: &str,
) -> anyhow::Result<Option<Money>> {
    let Some(s) = raw.map(str::trim).filter(|s| !s.is_empty()) else {
        return Ok(None);
    };
    let amount: f64 = s
        .parse()

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Upgrade the adapter to a version supporting the new BybitContractType variant
  2. Filter out symbols with unsupported contractType before calling parse_linear_instrument
  3. Extend the match in parse_linear_instrument to map or explicitly skip the new variant
  4. Check which symbol/contractType triggered it (the Debug output in the message) and exclude that category

Example fix

// before
other => Err(anyhow::anyhow!("unsupported linear contract variant: {other:?}")),
// after
other => {
    tracing::debug!(?other, "skipping unsupported linear contract variant");
    Ok(None)
}
Defensive patterns

Strategy: type-guard

Validate before calling

fn is_supported_linear(ct: &BybitContractType) -> bool {
    matches!(ct, BybitContractType::LinearPerpetual | BybitContractType::LinearFutures)
}

Type guard

fn as_supported_linear(ct: &BybitContractType) -> Option<&BybitContractType> {
    matches!(ct, BybitContractType::LinearPerpetual | BybitContractType::LinearFutures).then_some(ct)
}

Try / catch

match parse_linear_instrument(&def, &fee, ts_event, ts_init) {
    Ok(inst) => instruments.push(inst),
    Err(e) if e.to_string().contains("unsupported linear contract variant") => {
        tracing::debug!(symbol = %def.symbol, "skipping unsupported contract");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Bybit's instruments-info response contains a contractType value (e.g. a newly introduced product line) that deserializes into a BybitContractType variant outside LinearPerpetual/LinearFutures, and the symbol is routed through parse_linear_instrument.

Common situations: Bybit adding new contract types on v5 API (e.g. options-like or pre-market contracts appearing in the linear list); running an older adapter version against an updated exchange API; filtered category='linear' requests returning unexpected instruments.

Related errors


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