nautechsystems/nautilus_trader · error
Funding rates only available for perpetuals, not {instrument
Error message
Funding rates only available for perpetuals, not {instrument_id} What it means
Beyond the product-type check, subscribe_funding_rates verifies that a cached instrument matching the requested ID is actually a CryptoPerpetual. If the instrument is loaded in the client's cache but is another type (spot, option, futures contract), the subscription is rejected because funding rates are a perpetual-only concept in this adapter.
Source
Thrown at crates/adapters/bybit/src/data.rs:1135
);
Ok(())
}
fn subscribe_funding_rates(&mut self, cmd: SubscribeFundingRates) -> 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 || product_type == BybitProductType::Option {
anyhow::bail!("Funding rates not available for {product_type:?} instruments");
}
let guard = self.instruments.load();
if let Some(instrument) = guard.get(&instrument_id)
&& !matches!(instrument, InstrumentAny::CryptoPerpetual(_))
{
anyhow::bail!("Funding rates only available for perpetuals, not {instrument_id}");
}
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("funding");
});
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)
Solutions
- Use the exact perpetual instrument ID (CryptoPerpetual) when subscribing to funding rates
- Verify what instrument is registered under that ID in the client cache
- Load/refresh the correct perpetual instrument before subscribing
- Filter non-perpetual instruments out of automated funding-rate subscription loops
Example fix
// before
subscribe_funding_rates("BTCUSDT-27SEP26".into())? // dated future: bails
// after
subscribe_funding_rates("BTCUSDT-PERP".into())? // CryptoPerpetual Defensive patterns
Strategy: validation
Validate before calling
fn is_perp_cached(client: &BybitDataClient, id: InstrumentId) -> bool {
client.instruments.load().get(&id)
.map(|i| matches!(i, InstrumentAny::CryptoPerpetual(_)))
.unwrap_or(false)
} Type guard
fn is_perpetual(inst: &InstrumentAny) -> bool {
matches!(inst, InstrumentAny::CryptoPerpetual(_))
} Try / catch
if !is_perpetual_cached(&client, id) {
log::debug!("{id} is not a perpetual; skipping funding subscription");
} else {
client.subscribe_funding_rates(cmd)?;
} Prevention
- Ensure the perpetual instrument is loaded into the client cache before subscribing
- Verify the InstrumentAny variant registered under each ID
- Auto-discover perpetuals from the instruments response rather than hardcoding IDs
When it happens
Trigger: subscribe_funding_rates called with an instrument_id present in the client's instrument cache whose InstrumentAny variant is not CryptoPerpetual — e.g. an expiring future or an option instrument registered under that ID.
Common situations: Subscribing to funding rates for dated futures or options assuming perpetual-like behavior; instruments cached with a wrong/generic type after a load; mistyped instrument ID strings that resolve to a non-perpetual symbol.
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
- Funding rates not available for {product_type:?} instruments
- Funding rates not available for {product_type} instruments
- Funding rates are only available for Derive perpetual instru
- Batch cancel limit is {endpoint_limit} orders for {product_t
- Unspecified Bybit order side
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/e6f78931b21f50b1.
Report an issue: GitHub.