nautechsystems/nautilus_trader · error
{model_name} requires an option instrument
Error message
{model_name} requires an option instrument What it means
`check_option_instrument` guards option fee models by verifying the instrument is a CryptoOption or OptionContract. Any other instrument type (spot, futures, binary option, etc.) bails with '{model_name} requires an option instrument', since the model's fee math assumes option contracts.
Source
Thrown at crates/execution/src/models/fee.rs:658
Some(LiquiditySide::NoLiquiditySide) | None => anyhow::bail!("Liquidity side not set"),
};
check_fee_rate(Some(rate), "fee_rate")?;
Ok(rate)
}
fn check_fee_rate(rate: Option<Decimal>, name: &str) -> anyhow::Result<()> {
if rate.is_some_and(|rate| rate < Decimal::ZERO) {
anyhow::bail!("`{name}` must be greater than or equal to zero");
}
Ok(())
}
fn check_option_instrument(instrument: &InstrumentAny, model_name: &str) -> anyhow::Result<()> {
if !matches!(
instrument,
InstrumentAny::CryptoOption(_) | InstrumentAny::OptionContract(_)
) {
anyhow::bail!("{model_name} requires an option instrument");
}
Ok(())
}
fn commission_currency(instrument: &InstrumentAny) -> Currency {
if instrument.is_inverse() {
instrument.settlement_currency()
} else {
instrument.quote_currency()
}
}
#[cfg(test)]
mod tests {
use std::{cell::Cell, rc::Rc};
use nautilus_model::{
enums::{LiquiditySide, OrderSide, OrderType},View on GitHub (pinned to 18893faf8b)
Solutions
- Wire the option fee model only to CryptoOption/OptionContract instruments
- Dispatch fee models per instrument type when building the backtest/live config
- Add a startup validation pass that checks each fee model against its instruments
Example fix
// before
let fee = option_fee_model.get_commission(&order, qty, px, &fx_pair_instrument)?;
// after
if matches!(instrument, InstrumentAny::CryptoOption(_) | InstrumentAny::OptionContract(_)) {
let fee = option_fee_model.get_commission(&order, qty, px, &instrument)?;
} else {
let fee = maker_taker_model.get_commission(&order, qty, px, &instrument)?;
} Defensive patterns
Strategy: validation
Validate before calling
if !matches!(instrument, InstrumentAny::CryptoOption(_) | InstrumentAny::OptionContract(_)) {
// route to a non-option fee model
} Type guard
fn is_option_instrument(i: &InstrumentAny) -> bool {
matches!(i, InstrumentAny::CryptoOption(_) | InstrumentAny::OptionContract(_))
} Try / catch
match option_model.get_commission(&order, qty, px, &instrument) {
Ok(fee) => fee,
Err(e) if e.to_string().contains("option instrument") => generic_model_fee(),
Err(e) => return Err(e),
} Prevention
- Select fee models per instrument type when configuring strategies
- Validate model-instrument pairing at strategy startup
- Keep per-market fee model registries instead of one global model
When it happens
Trigger: Calling get_commission/get_commission_with_context on an option fee model with an InstrumentAny that is not CryptoOption or OptionContract — e.g. CurrencyPair, CryptoPerpetual, FuturesContract, or BinaryOption.
Common situations: Assigning one fee model to a multi-instrument portfolio; misconfigured backtest where the instrument cache returns the wrong instrument; copy-pasted setup reused across markets.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- ProbabilityPriceFeeModel requires a binary option instrument
- option_summary_family_subs mutex poisoned
- Invalid `OptionKind`, was '{invalid}'
- unsupported Derive instrument type for trades: {other:?}
- Unknown IB option right: {value}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/4940c0445bd11794.
Report an issue: GitHub.