nautechsystems/nautilus_trader · error

Invalid symbol format: missing base currency in '{symbol}'

Error message

Invalid symbol format: missing base currency in '{symbol}'

What it means

parse_base_quote_from_symbol splits an OKX instrument id like 'BTC-USDT' or 'BTC-USD-240329' on '-' and extracts base and quote. Although split() on a non-empty string always yields a first element, the code guards with ok_or_else; this 'missing base currency' error represents a malformed/empty symbol input where no base part could be extracted.

Source

Thrown at crates/adapters/okx/src/common/parse.rs:288

                OKXInstrumentType::Events
            }
        }
        _ if dash_count > 4 => OKXInstrumentType::Events,
        _ => OKXInstrumentType::Spot, // Default fallback
    }
}

/// Extracts base and quote currencies from an OKX symbol.
///
/// All OKX instrument symbols start with {BASE}-{QUOTE}, regardless of type.
///
/// # Errors
///
/// Returns an error if the symbol doesn't contain at least two parts separated by '-'.
pub fn parse_base_quote_from_symbol(symbol: &str) -> anyhow::Result<(&str, &str)> {
    let mut parts = symbol.split('-');
    let base = parts.next().ok_or_else(|| {
        anyhow::anyhow!("Invalid symbol format: missing base currency in '{symbol}'")
    })?;
    let quote = parts.next().ok_or_else(|| {
        anyhow::anyhow!("Invalid symbol format: missing quote currency in '{symbol}'")
    })?;
    Ok((base, quote))
}

/// Extracts the instrument family from an OKX symbol string.
///
/// All OKX derivative symbols encode the family as the first two segments:
/// `BTC-USD-250328-92000-C` -> `BTC-USD`, `BTC-USDT-SWAP` -> `BTC-USDT`.
///
/// # Errors
///
/// Returns an error if the symbol does not contain at least two dash-separated parts.
pub fn extract_inst_family(symbol: &str) -> anyhow::Result<Ustr> {
    let (base, quote) = parse_base_quote_from_symbol(symbol)?;
    Ok(Ustr::from(&format!("{base}-{quote}")))

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Validate the instrument id is non-empty and matches the OKX format BASE-QUOTE[-DATE] before calling (regex like ^[A-Za-z0-9]+-[A-Za-z0-9]+(-\d{6})?$).
  2. Check where the symbol originates — config instrument_ids, subscription messages, or position reports — and fix the empty source value.
  3. Use the instrument id exactly as OKX returns it (e.g. from the instruments endpoint) instead of hand-building the string.
  4. If OKX deserialization yields an empty instId, check the adapter's message schema against the current OKX API docs for renamed fields.

Example fix

// before
parse_base_quote_from_symbol(&inst_id)?;

// after
if inst_id.is_empty() || !inst_id.contains('-') {
    return Err(anyhow::anyhow!("invalid OKX instrument id: '{inst_id}'"));
}
parse_base_quote_from_symbol(&inst_id)?;
Defensive patterns

Strategy: validation

Validate before calling

fn valid_okx_symbol(s: &str) -> bool {
    !s.is_empty() && s.split('-').next().map(|p| !p.is_empty()).unwrap_or(false)
}

Try / catch

match parse_base_quote_from_symbol(symbol) {
    Ok((base, quote)) => (base, quote),
    Err(e) => return Err(anyhow::anyhow!("bad instrument id '{symbol}': {e}")),
}

Prevention

When it happens

Trigger: Called from extract_inst_family, parse_position_status_report, subscribe/unsubscribe_index_prices, or request_index_price with a symbol string that is empty or otherwise yields no base segment before the first '-' (empty string input is the practical trigger).

Common situations: Passing an empty instrument id from an uninitialized config or a subscription event with a blank instId; a bug upstream that forwards None-as-empty-string symbols; constructing symbols manually and forgetting the instType/instId convention; OKX payload field renamed so the symbol field read as empty.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


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