nautechsystems/nautilus_trader · error · anyhow::Error

base_coin is empty for symbol '{}'

Error message

base_coin is empty for symbol '{}'

What it means

When building a NautilusTrader instrument from a Bybit linear (USDT/USDC-margined) instrument definition, the parser requires base_coin to be a nonempty string because it is used to derive the base Currency of the instrument. An empty base_coin means the exchange payload is incomplete or malformed, so parse_linear_instrument fails fast with this anyhow::ensure! error including the symbol.

Source

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

        .build()
        .unwrap();

    Ok(InstrumentAny::CurrencyPair(instrument))
}

/// 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,
    )?;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check the Bybit instruments-info response for the symbol and confirm base_coin is populated
  2. Fix the deserialization/fixture so base_coin is mapped correctly from the API field
  3. Filter out instruments with empty base_coin before calling parse_linear_instrument
  4. Report/refresh stale cached instrument definitions that lack the coin fields

Example fix

// before
let inst = parse_linear_instrument(&BybitInstrumentLinear { symbol: "BTCUSDT".into(), base_coin: "".into(), ..def }, &fee, ts_event, ts_init)?;
// after
if def.base_coin.is_empty() {
    tracing::warn!(symbol = %def.symbol, "skipping instrument with empty base_coin");
    return Ok(None);
}
let inst = parse_linear_instrument(&def, &fee, ts_event, ts_init)?;
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

fn has_base_coin(def: &BybitInstrumentLinear) -> bool {
    !def.base_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 (or its callers: linear_instrument, request_instruments, position parsing) with a BybitInstrumentLinear whose base_coin field is empty — typically from a truncated or missing field in the exchange /v5/market/instruments-info response or a hand-constructed definition.

Common situations: Bybit API returning partial instrument data for newly listed or delisted symbols; deserialization defaults leaving base_coin empty when the JSON key is missing; test fixtures with stub instruments missing coin fields.

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/126791d85e0f6810. Report an issue: GitHub.