nautechsystems/nautilus_trader · error · anyhow::Error

quote_coin is empty for symbol '{}'

Error message

quote_coin is empty for symbol '{}'

What it means

parse_linear_instrument requires quote_coin to be nonempty because it derives the quote Currency (e.g. USDT) and pricing/instrument metadata for linear instruments. An empty quote_coin indicates an incomplete Bybit instrument definition, so the parser rejects it with this error naming the symbol.

Source

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

/// Parses a linear contract definition (perpetual or dated future) into a Nautilus instrument.
///
/// # Panics
///
/// Panics if the constructed instrument fails validation.
pub fn parse_linear_instrument(
    definition: &BybitInstrumentLinear,
    fee_rate: &BybitFeeRate,
    ts_event: UnixNanos,
    ts_init: UnixNanos,
) -> anyhow::Result<InstrumentAny> {
    // Validate required fields
    anyhow::ensure!(
        !definition.base_coin.is_empty(),
        "base_coin is empty for symbol '{}'",
        definition.symbol
    );
    anyhow::ensure!(
        !definition.quote_coin.is_empty(),
        "quote_coin is empty for symbol '{}'",
        definition.symbol
    );

    let base_currency = get_currency(definition.base_coin.as_str());
    let quote_currency = get_currency(definition.quote_coin.as_str());
    let settlement_currency = resolve_settlement_currency(
        definition.settle_coin.as_str(),
        base_currency,
        quote_currency,
    )?;

    let symbol = BybitSymbol::new(format!("{}-LINEAR", definition.symbol))?;
    let instrument_id = symbol.to_instrument_id();
    let raw_symbol = Symbol::new(symbol.raw_symbol());

    let price_increment = parse_price(&definition.price_filter.tick_size, "priceFilter.tickSize")?;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Verify the Bybit API response includes quote_coin for the symbol and fix the data source
  2. Correct the deserialization struct mapping so quote_coin is populated
  3. Skip instruments with empty quote_coin and log a warning instead of failing the batch
  4. Update test fixtures to include realistic quote_coin values

Example fix

// before
let def = BybitInstrumentLinear { symbol: "ETHUSDT".into(), quote_coin: "".into(), ..raw };
let inst = parse_linear_instrument(&def, &fee, ts_event, ts_init)?;
// after
let def = BybitInstrumentLinear { symbol: "ETHUSDT".into(), quote_coin: "USDT".into(), ..raw };
let inst = parse_linear_instrument(&def, &fee, ts_event, ts_init)?;
Defensive patterns

Strategy: validation

Validate before calling

if def.quote_coin.trim().is_empty() {
    return Err(anyhow::anyhow!("quote_coin missing for {}", def.symbol));
}

Type guard

fn has_quote_coin(def: &BybitInstrumentLinear) -> bool {
    !def.quote_coin.trim().is_empty()
}

Try / catch

match parse_linear_instrument(&def, &fee, ts_event, ts_init) {
    Ok(inst) => instruments.push(inst),
    Err(e) => { tracing::warn!(symbol = %def.symbol, "skipping instrument: {e:#}"); continue; }
}

Prevention

When it happens

Trigger: Calling parse_linear_instrument with a BybitInstrumentLinear whose quote_coin is empty — e.g. the /v5/market/instruments-info payload omitted quote_coin, or a constructed definition in tests/adapters missed the field.

Common situations: Partial exchange responses for new/delisted contracts; misconfigured field mapping in deserialization; fixtures copied from inverse instrument examples where quote semantics differ.

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/46ebca724085481d. Report an issue: GitHub.