nautechsystems/nautilus_trader · error
Invalid contract type '{}' for {}: expected 'linear' or 'inv
Error message
Invalid contract type '{}' for {}: expected 'linear' or 'inverse' What it means
OKX swap instruments must declare a contract type of either 'linear' or 'inverse'. This error is raised by parse_swap_instrument when the OKX instruments response contains a SWAP instrument whose ct_type field is missing or mapped to OKXContractType::None, making it impossible to determine settlement direction. The raw ct_type value and inst_id are embedded in the message for diagnosis.
Source
Thrown at crates/adapters/okx/src/common/parse.rs:2166
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!(
"Invalid contract type '{}' for {}: expected 'linear' or 'inverse'",
definition.ct_type,
definition.inst_id
)
}
};
if definition.tick_sz.is_empty() {
anyhow::bail!("`tick_sz` is empty for {}", definition.inst_id);
}
let price_increment = Price::from_str(&definition.tick_sz).map_err(|e| {
anyhow::anyhow!(
"Failed to parse `tick_sz` '{}' into Price for {}: {e}",
definition.tick_sz,
definition.inst_id
)
})?;View on GitHub (pinned to 18893faf8b)
Solutions
- Check the raw OKX /api/v5/public/instruments?instType=SWAP payload for the offending inst_id and confirm what ctType value OKX actually returns
- Update the OKXContractType deserialization in the adapter to map any new ctType value OKX introduced (e.g. new linear/inverse variants) instead of falling through to None
- Fix the code or fixture that constructs the instrument definition so ct_type is always Linear or Inverse for SWAP instruments
- If the instrument is genuinely unusable, filter it out of the instruments response before parsing
Example fix
// before
OKXContractType::None => {
anyhow::bail!("Invalid contract type '{}' for {}: expected 'linear' or 'inverse'", definition.ct_type, definition.inst_id)
}
// after
// map the new OKX ctType in the deserializer so it never reaches None:
// "SWAP" new variant => OKXContractType::Linear, or filter unknown ctTypes upstream Defensive patterns
Strategy: validation
Validate before calling
fn valid_swap(def: &OKXInstrumentDef) -> bool { matches!(def.ct_type, OKXContractType::Linear | OKXContractType::Inverse) }
if !valid_swap(&definition) { skip_or_log(&definition.inst_id); } Type guard
fn has_contract_type(def: &OKXInstrumentDef) -> bool { !matches!(def.ct_type, OKXContractType::None) } Try / catch
match parse_instrument_any(&def) {
Err(e) if e.to_string().contains("Invalid contract type") => { log::warn!("skipping {}: {e}", def.inst_id); }
Err(e) => return Err(e),
Ok(inst) => instruments.push(inst),
} Prevention
- Keep the OKXContractType deserializer updated with OKX v5 API changelog entries
- Always set ct_type when constructing instrument definitions in fixtures
- Log unknown ctType values at deserialize time so drift is detected early
When it happens
Trigger: Calling parse_instrument_any (or parse_swap_instrument directly) on an OKX InstrumentsResponse where a SWAP entry has ct_type OKXContractType::None — e.g. OKX returned an empty/unknown ctType string, or the definition was constructed programmatically without setting ct_type.
Common situations: OKX adds a new contract type not yet handled by the adapter's ct_type deserializer, falling through to None; mocked/fixture instrument definitions in tests or local replay data built without ctType; API schema drift between OKX v5 versions.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Invalid tickSize of 0 for symbol '{}', cannot create instrum
- `tick_sz` is empty for {}
- `lot_sz` is empty for {}
- Empty underlying for {inst_id}: instrument may be pre-open o
- `settle_ccy` or `quote_ccy` is required for EVENTS instrumen
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/09dc9d26d48a053a.
Report an issue: GitHub.