nautechsystems/nautilus_trader · error

Mark prices not available for Spot instruments

Error message

Mark prices not available for Spot instruments

What it means

This error is raised when subscribing to mark prices for a Spot instrument on Bybit. Bybit's WebSocket does not provide mark-price streams for Spot product types, so the adapter rejects the subscription early. The subscription is only valid for Linear, Inverse, and Option instruments.

Solutions

  1. Use Linear (perpetual) or Inverse instrument IDs instead of Spot for mark-price subscriptions
  2. Skip mark-price subscription logic for Spot instruments in your strategy configuration
  3. Use last trade price / ticker data for Spot instruments instead of mark prices

Example fix

// before
let instrument_id = InstrumentId::from("BTCUSDT.SBYBIT"); // Spot
data_engine.subscribe_mark_prices(instrument_id);
// after
let instrument_id = InstrumentId::from("BTCUSDT-PERP.SBYBIT"); // Linear
data_engine.subscribe_mark_prices(instrument_id);
Defensive patterns

Strategy: validation

Validate before calling

let instrument = cache.instrument(&instrument_id).expect("instrument not found");
if instrument.asset_class() == AssetClass::SPOT /* or product type Spot */ {
    // skip mark price subscription, use ticker data instead
    return Ok(());
}
data_engine.subscribe_mark_prices(instrument_id)?;

Try / catch

match data_engine.subscribe_mark_prices(instrument_id) {
    Err(e) if e.to_string().contains("Mark prices not available for Spot") => {
        // fall back to quote/ticker data
    }
    r => r?,
}

Prevention

When it happens

Trigger: Calling subscribe_mark_prices (via DataEngine.subscribe_mark_prices or SubscribeMarkPrices command) with an instrument_id whose symbol suffix maps to Bybit Spot (e.g. BTCUSDT.SBYBIT resolved to Spot).

Common situations: Configuring a strategy that assumes mark prices exist for all instruments; reusing a data pipeline built for perp/futures symbols with Spot symbols; get_product_type_for_instrument returning Spot from the symbol suffix.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at crates/adapters/bybit/src/data.rs:1170

                async move {
                    ws.subscribe_ticker(instrument_id)
                        .await
                        .context("ticker subscription for funding rates")
                },
                "funding rate subscription",
            );
        }
        Ok(())
    }

    fn subscribe_mark_prices(&mut self, cmd: SubscribeMarkPrices) -> anyhow::Result<()> {
        let instrument_id = cmd.instrument_id;
        let product_type = self
            .get_product_type_for_instrument(instrument_id)
            .unwrap_or(BybitProductType::Linear);

        if product_type == BybitProductType::Spot {
            anyhow::bail!("Mark prices not available for Spot instruments");
        }

        let mut should_subscribe = false;
        self.ticker_subs.rcu(|m| {
            let entry = m.entry(instrument_id).or_default();
            should_subscribe = entry.is_empty();
            entry.insert("mark_prices");
        });

        if should_subscribe {
            let ws = self
                .get_ws_client_for_product(product_type)
                .context("no WebSocket client for product type")?
                .clone();

            self.spawn_ws(
                async move {
                    ws.subscribe_ticker(instrument_id)

View on GitHub (pinned to 18893faf8b)