nautechsystems/nautilus_trader · warning

empty funding_rate for {instrument_id} (dated futures do not

Error message

empty funding_rate for {instrument_id} (dated futures do not have funding rates)

What it means

Bybit's linear ticker payload contained an empty `funding_rate` string. For dated (delivery) futures Bybit sends an empty funding rate because those instruments have no funding; the adapter surfaces this explicitly rather than parsing an empty string into a bogus rate.

Source

Thrown at crates/adapters/bybit/src/websocket/parse.rs:467

/// Parses a linear ticker payload into a [`FundingRateUpdate`].
///
/// # Errors
///
/// Returns an error if funding rate, funding interval or next funding time fields are missing or cannot be parsed.
pub fn parse_ticker_linear_funding(
    data: &BybitWsTickerLinear,
    instrument_id: InstrumentId,
    ts_event: UnixNanos,
    ts_init: UnixNanos,
) -> anyhow::Result<FundingRateUpdate> {
    let funding_rate_str = data
        .funding_rate
        .as_ref()
        .context("Bybit ticker missing funding_rate")?;

    if funding_rate_str.is_empty() {
        anyhow::bail!(
            "empty funding_rate for {instrument_id} (dated futures do not have funding rates)"
        );
    }

    let funding_rate = funding_rate_str
        .as_str()
        .parse::<Decimal>()
        .with_context(|| {
            format!("invalid funding_rate value '{funding_rate_str}' for {instrument_id}")
        })?;

    let funding_interval = if let Some(funding_interval_hour) = &data.funding_interval_hour {
        let funding_interval_hour = funding_interval_hour
            .as_str()
            .parse::<u16>()
            .context("invalid funding_interval_hour value")?;
        Some(
            funding_interval_hour

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Only request funding rates for perpetual instruments; skip dated futures tickers before parsing.
  2. Treat the error as 'instrument has no funding' and continue processing the stream instead of failing.
  3. Check `instrument_info`/contract type when subscribing so delivery contracts are excluded from funding handling.

Example fix

// before: parse every linear ticker
let fr = parse_ticker_linear_funding(&data, instrument_id)?;
// after: skip dated futures
if !is_perpetual(instrument_id) {
    return Ok(None); // dated futures have no funding rate
}
let fr = parse_ticker_linear_funding(&data, instrument_id)?;
Defensive patterns

Strategy: validation

Validate before calling

if !instrument_id.to_string().contains("-PERP") {
    return Ok(None); // dated futures have no funding rate
}

Type guard

fn is_perpetual(instrument_id: &InstrumentId) -> bool {
    instrument_id.symbol.to_string().ends_with("-PERP")
}

Try / catch

match parse_ticker_linear_funding(&data, instrument_id) {
    Ok(fr) => publish_funding(fr),
    Err(e) if e.to_string().contains("empty funding_rate") => {
        tracing::debug!("{instrument_id} is dated; no funding rate");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: `parse_ticker_linear_funding` is called on a ticker message for a dated/delivery futures instrument whose `funding_rate` field is `Some("")`.

Common situations: Subscribing to tickers on dated futures (e.g. quarterly expiries) where funding does not apply; running a perp-focused consumer against delivery contracts.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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