nautechsystems/nautilus_trader · error
Invalid underlying '{}' for {}: expected format 'BASE-QUOTE'
Error message
Invalid underlying '{}' for {}: expected format 'BASE-QUOTE' What it means
parse_swap_instrument splits the OKX `uly` (underlying) string on '-' to derive base and quote currencies, expecting the 'BASE-QUOTE' format. If the split yields no dash-separated pair, the library throws this error. `validate_underlying` has already rejected an empty underlying, so this fires only when a non-empty uly lacks the expected structure.
Source
Thrown at crates/adapters/okx/src/common/parse.rs:2148
///
/// Returns an error if the instrument definition cannot be parsed.
///
/// # Panics
///
/// Panics if the constructed instrument fails validation.
pub fn parse_swap_instrument(
definition: &OKXInstrument,
margin_init: Option<Decimal>,
margin_maint: Option<Decimal>,
maker_fee: Option<Decimal>,
taker_fee: Option<Decimal>,
ts_init: UnixNanos,
) -> anyhow::Result<InstrumentAny> {
validate_underlying(definition.inst_id, definition.uly)?;
let context = format!("SWAP instrument {}", definition.inst_id);
let (base_currency, quote_currency) = definition.uly.split_once('-').ok_or_else(|| {
anyhow::anyhow!(
"Invalid underlying '{}' for {}: expected format 'BASE-QUOTE'",
definition.uly,
definition.inst_id
)
})?;
let instrument_id = parse_instrument_id(definition.inst_id);
let raw_symbol = Symbol::from_ustr_unchecked(definition.inst_id);
let base_currency = Currency::get_or_create_crypto_with_context(base_currency, Some(&context));
let quote_currency =
Currency::get_or_create_crypto_with_context(quote_currency, Some(&context));
let settlement_currency =
Currency::get_or_create_crypto_with_context(definition.settle_ccy, Some(&context));
let is_inverse = match definition.ct_type {
OKXContractType::Linear => false,
OKXContractType::Inverse => true,
OKXContractType::None => {
anyhow::bail!(View on GitHub (pinned to 18893faf8b)
Solutions
- Print definition.uly for the failing inst_id and check it contains exactly a 'BASE-QUOTE' pair like "BTC-USD".
- Fix the source data so uly matches OKX's 'BTC-USD-TIMING' underlying format (the parser splits on the first '-').
- Confirm validate_underlying passed; if uly should be empty, fix the instrument definition instead.
- If a new OKX format is genuinely in play, update the parser's split logic upstream.
Example fix
// before "uly": "BTCUSD" // after "uly": "BTC-USD"
Defensive patterns
Strategy: validation
Validate before calling
fn has_base_quote_uly(uly: &str) -> bool {
!uly.trim().is_empty() && uly.contains('-') && uly.split('-').next().map_or(false, |b| !b.is_empty())
}
// guard: assert!(has_base_quote_uly(&definition.uly), "bad uly: {}", definition.uly); Type guard
fn parse_uly_pair(uly: &str) -> Option<(&str, &str)> {
uly.split_once('-')
} Try / catch
match parse_instrument_any(&definition, ts_init) {
Ok(inst) => inst,
Err(e) if e.to_string().contains("expected format 'BASE-QUOTE'") => {
tracing::warn!(inst_id = %definition.inst_id, "skipping SWAP with malformed uly '{}': {e}", definition.uly);
continue;
}
Err(e) => return Err(e),
} Prevention
- Always model OKX underlyings as 'BASE-QUOTE' strings (e.g. BTC-USD) exactly as the exchange reports them.
- Run validate_underlying plus a contains('-') check before constructing definitions.
- Derive uly from the live instruments response instead of composing it manually.
- Add a unit test asserting every fixture uly splits on '-'.
When it happens
Trigger: Calling parse_instrument_any -> parse_swap_instrument with a definition whose uly is non-empty but does not contain a '-' (e.g. "BTCUSD" instead of "BTC-USD", or a single-token underlying).
Common situations: Fixture data written without the exchange's BASE-QUOTE convention; a new OKX instrument family whose underlying uses a different separator; manually constructed definitions in tests or custom adapters feeding the parser.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Invalid contract type '{}' for {}: expected 'linear' or 'inv
- `settle_ccy` or `quote_ccy` is required for EVENTS instrumen
- Failed to parse `tick_sz` '{}' into Price for {}: {e}
- Failed to parse `max_mkt_sz` '{}' for {}: {e}
- `exp_time` is required for {}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/4cfff323b805104f.
Report an issue: GitHub.